分布式事务篇-2.4 Spring-Boot整合Seata

文章目录

  • 前言
  • 一、pom jar导入:
  • 二、项目配置:
    • 2.1 配置 说明:
      • 2.1 .1 seata server 端:
      • 2.1 .2 seata client 端:
    • 2.2 开启seata 对于数据源的代理:
    • 2.3 seata-client 的注册中心:
    • 2.4 seata-client 的配置中心:
    • 2.5 去掉手写的数据源代理和feign代理:
  • 三、项目使用:
    • 3.1 AT 模式使用:
    • 3.2 XA 模式使用:
    • 3.3 TCC 模式使用:
  • 四、总结:
  • 五、参考:


前言

在了解了Seata 的工作原理后,如何在springboot 项目中进行整合使用,本文进行阐述。


提示:本文使用 seata 版本 :1.5 ;在整合之前 你需要先要部署seate 的服务

一、pom jar导入:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.14</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>spring-seata-storage</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-seata-storage</name><description>spring-seata-storage</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId><optional>true</optional><version>3.1.6</version></dependency><!-- mysql --><!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version><!-- <version>5.1.49</version>--></dependency><!-- https://mvnrepository.com/artifact/net.sf.jsqlparser/jsqlparser --><dependency><groupId>net.sf.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>0.8.0</version></dependency><dependency><groupId>io.swagger</groupId><artifactId>swagger-annotations</artifactId><version>1.6.2</version></dependency><!-- https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter --><!-- <dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.5.2</version></dependency>--><!--处理 在SpringBoot 2.4.x的版本之后,对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,需要导入如下的依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId><version>3.1.6</version></dependency><!-- seata 使用nacos 作为配置中心和 注册中心时 使用  --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>2021.0.5.0</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2021.0.5.0</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><!-- 里面已经集成服务间调用X-id的传递,包括FeignClient的重写,如果在之前自定义封装过Feign,注意启动冲突--><artifactId>spring-cloud-starter-alibaba-seata</artifactId><version>2021.0.5.0</version><exclusions><!--去除低版本--><exclusion><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId></exclusion></exclusions></dependency><!-- https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter --><dependency><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId><version>1.6.1</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><mainClass>com.example.springseata.springseatastorage</mainClass></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins><resources><resource><directory>src/main/resources</directory><filtering>true</filtering></resource></resources></build></project>

jar 目的:

  • spring-boot-starter-web: 使用 浏览器进行 http 访问;
  • lombok: 生成 get set 等方法,使代码更加简洁;
  • spring-boot-starter-test: 可以进行单元测试;
  • spring-cloud-starter-openfeign: 可以使用feign 接口进行服务间的http 通信;
  • mybatis-plus-boot-starte,mysql-connector-java ,jsqlparser:导入mysql-plus 进行 增删改查;
  • swagger-annotations: 类和方法的说明;
  • spring-cloud-starter-bootstrap :在SpringBoot 2.4.x的版本之后,对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持;
  • spring-cloud-starter-alibaba-nacos: seata 使用nacos 作为配置中心和 注册中心时 使用;
  • spring-cloud-starter-alibaba-seata: 导入cloud对饮的jar 让其帮助进行 分布式事务xid 的传递;
  • seata-spring-boot-starter : seata 的核销服务jar;

springcloud ,springboot,springcloud-alibaba 版本对应:版本说明

二、项目配置:

2.1 配置 说明:

目的: 了解seat 客户端和服务端的 关系,清楚其配置的含义;

2.1 .1 seata server 端:

  • seata server 的存储模式:
    存储模式指定了Seata Server用于存储事务和元数据的方式,这个只有在seata 服务端才有。Seata Server支持三种存储模式:file、db和Redis。列如 当开始事务时需要生成全局事务id Xid ,在生成后就需要Seata 服务进行存储,所以他是Seata Server的重要组成部分;

  • seata server 的配置中心:
    配置中心的作用:用于配置 Seata Server的相关参数, Seata Server 端在启动的时候也可以配置很多参数,如果把这些参数都放到 Seata Server 中,每次修改度需要连接到Seata Server 的服务器,然后对其配置文件进行修改,如果把这个参数放到 配置中心如config ,zk,nacos 就可以在配置中心进行修改,更加的方便;

  • seata server 的注册中心:
    Seata Server 的注册中心是用于存储和管理 Seata 事务参与者的信息的组件;多个Seata Server 可以成为一个集群,然后注册到zk,eureka,nacos 里,这样方便集群的管理;

2.1 .2 seata client 端:

  • seata client 的配置中心:
    同seata-sever 端相同,客户端在启动的时候也可以进行参数的配置,所以可以在客户端我们也可以 将参数放到 config ,zk,nacos 进行配置;

  • seata client 的注册中心:
    seata 客户端的注册中心,用于服务端的发现,一个重要的信息就是,可以将seata 客户端和seata 服务端 注册到相同的地方,已nacos 为例:服务端和客户端 注册到相同命名空间,相同分组,相同应用,此时客户端会动态的发现 seata 服务的地址,此时不需要在显示的设置 seata 服务断的地址;
    Seata 客户端在启动时会从 Nacos 服务获取 service.vgroupMapping.your-service-group 定义的服务群组实例,这需要和 Seata 服务端的配置保持一致。以下三个参数需要和 Seata 服务端保持一致:application:, group, namespace

2.2 开启seata 对于数据源的代理:

目的:让 seata 接管数据源,然后才能协调各个微服务的本地事务;

seata:enabled: true # spring 自动装配enable-auto-data-source-proxy: true # 开启数据源自动代理transport:enable-client-batch-send-request: true #客户端事务消息请求是否批量合并发送,默认true,false单条发送tx-service-group: my_tx_group # 事务分组application-id: storageservice:vgroup-mapping:my_tx_group: default
#    grouplist:
#      default: localhost:8091
  • tx-service-group 定义事务分组,可以自定义,多个微服务只有在同一个事务分组中,分布式事务才能生效,也就是多个微服务改参数要保持一致;
  • application-id 该服务事务id ,同一分组下的 的微服务 需要进行不同的定义;
  • servicevgroup-mapping 定义改事务分组 连接的seata 服务端 集群的名称,改名称需要和seata server 定义的集群名称保持一致;
    在这里插入图片描述
  • grouplist 中 default 为集群的名称,后面的为集群seata-server 端的地址,注意 这中连接模式只在 seata 客户端为 file 模式下生效; 其他方式如nacos ,需要配置使得 seata-server 和seata-client 都注册在相同命名空间,相同分组,相同application 下,这样seata-client 就可以动态的发现seata-server 的实例地址;

2.3 seata-client 的注册中心:

目的: 了解本地springboot 服务如何连接到 seata server 端

客户端和服务端 seata 都是默认已file 作为注册中心:

  • file
    seata-server 服务端 注册中心使用的file 本地模式,则seata 客户端 也需要使用file注册模式:
    此时需要配置 seata.service.grouplist.default=127.0.0.1:8091 用于客户端连接 seata 服务端;

  • nacos
    seata-server 服务端 注册中心使用的nacos,则seata 客户端 也需要使用nacos注册模式:

 seata-server 服务端 注册中心使用的nacos,则seata 客户端 也需要使用nacos注册模式:
seata:enabled: true # spring 自动装配enable-auto-data-source-proxy: true # 开启数据源自动代理transport:enable-client-batch-send-request: true #客户端事务消息请求是否批量合并发送,默认true,false单条发送tx-service-group: my_tx_groupapplication-id: storageservice:vgroup-mapping:my_tx_group: default
#    grouplist:
#      default: localhost:8091registry:#    type: filetype: nacosnacos:application: seata-serverserver-addr: localhost:8848group: SEATA_GROUPnamespace: 7f2765bc-d8c1-4b49-b706-8c292d2ffac9username: nacospassword: nacos

注意 application,server-addr,group,namespace,username,password 客户端和服务端报纸一致;

2.4 seata-client 的配置中心:

目的: 了解本地springboot 如何对seata 进行参数配置

客户端和服务端 seata 都是默认已file 作为配置中心,他们的只是用作参数的配置使用,所以他们各自是独立的;

  • file
    seata 客户端的默认配置;
  • nacos
    使用nacos 作为配置中心 :
seata:enabled: true # spring 自动装配enable-auto-data-source-proxy: true # 开启数据源自动代理transport:enable-client-batch-send-request: true #客户端事务消息请求是否批量合并发送,默认true,false单条发送tx-service-group: my_tx_groupapplication-id: storageservice:vgroup-mapping:my_tx_group: default
#    grouplist:
#      default: localhost:8091config:type: nacos
#    type: filenacos:server-addr: localhost:8848namespace: c0befc56-f31b-4de6-929b-6f75604992d1
#      namespace: 7f2765bc-d8c1-4b49-b706-8c292d2ffac9group: DEFAULT_GROUPusername: nacospassword: nacos##if use MSE Nacos with auth, mutex with username/password attribute#access-key: ""#secret-key: ""data-id: seata.properties

本文测试时虽然在 nacos 中创建了seata.properties 的配置文件但是其 配置的参数没有起作用;
在这里插入图片描述
会提示无法找到service.vgroupMapping.my_tx_group(my_tx_group 为定义的分组名称)的集群,通过创建 service.vgroupMapping.my_tx_group 配置文件 并且定义default 得以解决,目前没有找到其它解决办法;
在这里插入图片描述

2.5 去掉手写的数据源代理和feign代理:

  • seata DataSourceProxy 的代理:因为在其配置文件中已经开启了自动代理

seata:enabled: true # spring 自动装配enable-auto-data-source-proxy: true # 开启数据源自动代理
所以需要去重 手动加入的代理,防止冲突,导致 事务失效

在这里插入图片描述

  • feign 接口的代理:
    因为引入的spring-cloud-starter-alibaba-seata 已经对feign 进行了xid 的处理
<dependency><groupId>com.alibaba.cloud</groupId><!-- 里面已经集成服务间调用X-id的传递,包括FeignClient的重写,如果在之前自定义封装过Feign,注意启动冲突--><artifactId>spring-cloud-starter-alibaba-seata</artifactId><version>2021.0.5.0</version><exclusions><!--去除低版本--><exclusion><groupId>io.seata</groupId><artifactId>seata-spring-boot-starter</artifactId></exclusion></exclusions>
</dependency>

所以可以去除 手动增加的对于feign 接口xid 的特殊处理防止冲突:
在这里插入图片描述

三、项目使用:

3.1 AT 模式使用:

seata 客户端的事务模式默认使用AT 模式;通过以下两个步骤配置就可使用:

  • 在每个 数据库中增加undo_log 表,用于AT 模式事务日志记录使用:
CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
  • 在不同服务中都完成seata 的集群 ,然后在对应的业务实现中增加@GlobalTransactional(rollbackFor =
    Exception.class) 注解:
    在这里插入图片描述

3.2 XA 模式使用:

  • mysql 开启XA协议:
SHOW VARIABLES LIKE 'innodb_support_xa';

在这里插入图片描述
如果没有开通,则打开 MySQL 配置文件 my.cnf 或 my.ini。在文件中找到 [mysqld] 部分,并在该部分下添加以下行:

[mysqld]
innodb_support_xa = 1

保存配置文件并重启 MySQL 服务;

  • 显示设置 模式为XA 模式,代码层面无需变动;
 seata.data-source-proxy-mode=XA

3.3 TCC 模式使用:

根据两阶段行为模式的不同,我们将分支事务划分为 Automatic (Branch) Transaction Mode 和 TCC (Branch) Transaction Mode.

AT 模式(参考链接 TBD)基于 支持本地 ACID 事务 的 关系型数据库:

一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
相应的,TCC 模式,不依赖于底层数据资源的事务支持:

一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
二阶段 commit 行为:调用 自定义 的 commit 逻辑。
二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。

  • tcc 事务记录表:tcc_fence_log
CREATE TABLE `tcc_fence_log` (`xid` varchar(128) NOT NULL COMMENT 'global id',`branch_id` bigint(20) NOT NULL COMMENT 'branch id',`action_name` varchar(64) NOT NULL COMMENT 'action name',`status` tinyint(4) NOT NULL COMMENT 'status(tried:1;committed:2;rollbacked:3;suspended:4)',`gmt_create` datetime(3) NOT NULL COMMENT 'create time',`gmt_modified` datetime(3) NOT NULL COMMENT 'update time',PRIMARY KEY (`xid`,`branch_id`),KEY `idx_gmt_modified` (`gmt_modified`),KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  • 订单服务 java demo:
    IOrderService:
public interface IOrderService extends IService<Order> {Boolean orderCreate(OrderReqDto reqDto);
}

实现类:

@Override
@GlobalTransactional(rollbackFor = Exception.class)public Boolean orderCreate(OrderReqDto reqDto) {log.error("Seata全局事务id=================>{}", RootContext.getXID());// stock服务未报错,order服务报错try {// 扣减库存-通过fegin 接口进行调用storageFeignApi.tccSumGoodNum(reqDto.getByGoods());} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}// 订单创建Order order = new Order();order.setAccountId("123").setMoney(reqDto.getOrderMoney());this.save(order);return true;}

controller:

@ResponseBody@PostMapping("/tcc/sure")public Boolean orderCreate(@RequestBody OrderReqDto reqDto) throws SQLException {return orderService.orderCreate(reqDto);}
  • 库存服务 java demo:
    controller:
 @ResponseBody@PostMapping(value = "/tcc/sumGoodNum")public boolean tccSumGoodNum(@RequestBody List<GoodDto> param){return  tccStorageService.deduct(param);}

ITccStorageService:

package com.example.springseatastorage.service;import com.example.springseatastorage.controller.dto.GoodDto;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;import java.util.List;@LocalTCC
public interface ITccStorageService {/*** 减库存* useTCCFence=true 为开启防悬挂* @param param*/@TwoPhaseBusinessAction(name = "deduct", commitMethod = "busCommit", rollbackMethod = "busRollback", useTCCFence = true)boolean deduct(@BusinessActionContextParameter(paramName = "param")  List<GoodDto>param);/*** 提交事务** @param actionContext* @return*/boolean busCommit(BusinessActionContext actionContext);/*** 回滚事务** @param actionContext* @return*/boolean busRollback(BusinessActionContext actionContext);
}

ITccStorageServicempl:

package com.example.springseatastorage.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.springseatastorage.controller.dto.GoodDto;
import com.example.springseatastorage.entity.Storage;
import com.example.springseatastorage.service.IStorageService;
import com.example.springseatastorage.service.ITccStorageService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;@Slf4j
@Service
public class ITccStorageServicempl implements ITccStorageService {@Autowiredprivate IStorageService storageService;@Override@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)public boolean deduct(List<GoodDto> param) {log.error("Seata全局事务id=================>{}", RootContext.getXID());Map<String, Integer> good = param.stream().collect(Collectors.toMap(GoodDto::getGoodId, GoodDto::getBuyNum));LambdaQueryWrapper<Storage> wrapper = new LambdaQueryWrapper<>();wrapper.in(Storage::getGoodId, param.stream().map(e -> e.getGoodId()).collect(Collectors.toList()));List<Storage> storages = storageService.list(wrapper);storages.stream().forEach(e -> {e.setGoodNum(e.getGoodNum() - good.get(e.getGoodId()));});storageService.updateBatchById(storages);return true;}@Overridepublic boolean busCommit(BusinessActionContext actionContext) {log.info("busCommit xid = " + actionContext.getXid() + "提交成功");return true;}@Overridepublic boolean busRollback(BusinessActionContext actionContext) {// 编写对应的业务数据进行回滚List<GoodDto> param = actionContext.getActionContext("param", List.class);
//        int count = actionContext.getActionContext("count", Integer.class);
//        LambdaQueryChainWrapper<Stock> eq = lambdaQuery().eq(Stock::getCommodityCode, commodityCode);
//        Long count1 = eq.one().getCount();
//        // 扣了多少数,需要重新添加回去
//        lambdaUpdate().set(Stock::getCount, count + count1)
//                .eq(Stock::getCommodityCode, commodityCode)
//                .update();log.info("busRollback xid = " + actionContext.getXid() + "回滚成功");return true;}
}

四、总结:

本文通过springboot 项目整合seata 然后 通过 AT,XA,TCC 事务模式,模拟实现分布式事务。

五、参考:

1 Seata新手部署指南;
2 版本说明;
3 Seata 事务模式;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/59476.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【第四阶段】kotlin语言的mutator函数学习

1.mutator特性1&#xff1a;使用list可以直接 - fun main() {val list mutableListOf(123,456,789)//特性1 可是直接使用list -list 111list-123println(list) }执行结果 2.mutator特性2&#xff1a;removeIF() 如果实现是true 会自动遍历整个集合&#xff0c;一个一个的移除…

新亮点!安防视频监控/视频集中存储/云存储平台EasyCVR平台六分屏功能展示

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

【Robot Framework】发送GET和POST请求

做接口自动化时&#xff0c;经常要使用GET与POST请求&#xff0c;那么如何使用RF发送对应的请求呢&#xff1f; 一、安装RequestsLibrary pip install robotframework-requests安装以后&#xff0c;导入到对应的测试套件或测试用例中. 本次主要介绍通过RequestsLibrary来实现…

【状压+概率DP】CF678 E

Problem - E - Codeforces 题意&#xff1a; 思路&#xff1a; 首先&#xff0c;n < 18&#xff0c;应当想到状压 很明显&#xff0c;这里可以使用状压DP 设 dp[s][i] 表示&#xff0c;现在选的方案为 s &#xff0c;且我是 i 的最终胜利的概率是多少 重要的是转移 这是…

数学建模——校园供水系统智能管理

import pandas as pd data1pd.read_excel("C://Users//JJH//Desktop//E//附件_一季度.xlsx") data2pd.read_excel("C://Users//JJH//Desktop//E//附件_二季度.xlsx") data3pd.read_excel("C://Users//JJH//Desktop//E//附件_三季度.xlsx") data4…

飞天使-python的模块与包与装饰器

文章目录 模块与包标准模块第三方模块自定义模块 高级语法切片迭代器/生成器高级模式&#xff08;闭包&#xff09;高级模式&#xff08;装饰器&#xff09; 参考视频 模块与包 标准模块 import os print(os.getcwd())import sys print(sys.argv) print(sys.platform) print(…

ETC reset

ETC重新激活 换前挡风玻璃膜会把ETC设备拿下来&#xff0c;需要到【ETC服务中心】重新【粘上去】&#xff0c;另外需要工作人员用手持终端【重新激活】 ETC 背面有个 【白色】开关小柱子&#xff0c;一旦拆下来就失效&#xff0c;因为这个开关弹出来了 截面图看就是这样的&…

万人在线,一站式自动化运维 SysOM 3.0重磅发布!龙蜥社区系统运维 MeetUp 回顾来了

8 月 12 日&#xff0c;由龙蜥社区系统运维 SIG 主办&#xff0c;乘云数字协办的&#xff0c;主题为“观测&#xff0c;让运维更简单&#xff01;”的系统运维 MeetUp 于杭州圆满结束。来自乘云数字、谐云科技、乐维、云杉网络、擎创科技、观测云、阿里云以及浙江大学等众多厂商…

Linux 多线程同步机制(上)

文章目录 前言一、线程同步二、互斥量 mutex三、死锁总结 前言 一、线程同步 在多线程环境下&#xff0c;多个线程可以并发地执行&#xff0c;访问共享资源&#xff08;如内存变量、文件、网络连接 等&#xff09;。 这可能导致 数据不一致性, 死锁, 竞争条件等 问题。 为了解…

医院常见的HIS、CIS、LIS、EMR、PACS、RIS医疗信息化中的介绍

医院常见的HIS、CIS、LIS、EMR、PACS、RIS分别是&#xff1a; HIS&#xff08;Hospital Information System&#xff09;&#xff1a;医院信息系统&#xff0c;是医院管理信息化的核心系统&#xff0c;包括病人管理、医生管理、药品管理、医疗设备管理、财务管理等多个方面&am…

Unity插件---Dotween

1.什么是DOTween DoTween 是由 Demigiant 开发的&#xff0c;被广泛应用于 Unity 游戏开发中。它是一个流行的动画插件&#xff0c;被许多开发者用于创建流畅、高效的动画效果&#xff0c;提升游戏体验。 2.DOTween的初始配置 ①set up 首先找到DOTween Unity Panel 的面板 点…

c# 本地化中英文切换

区域 线程默认区域为当前计算机所选区域 设置当前区域&#xff1a; Thread.CurrentThread.CurrentCulture new CultureInfo(“zh-cn”); 获取当前区域&#xff1a; Console.WriteLine(Thread.CurrentThread.CurrentCulture.ToString()); 区域名称&#xff1a; “zh-cn” 中文…

数据结构(Java实现)-栈和队列

栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 先进后出 栈的使用 栈的模拟实现 上述的主要代码 public class MyStack {private int[] elem;private int usedSize;public MyStack() {this.elem new int[5];}Overridepublic …

【数学建模竞赛】各类题型及解题方案

评价类赛题建模流程及总结 建模步骤 建立评价指标->评价体系->同向化处理&#xff08;都越多越好或越少越少&#xff09;->指标无量纲处理 ->权重-> 主客观->合成 主客观评价问题的区别 主客观概念主要是在指标定权时来划分的。主观评价与客观评价的区别…

Django实现音乐网站 ⒁

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是歌手页-全部歌手页功能开发。 目录 分出首页样式内容 创建首页样式文件 首页引入样式文件 全部歌手列表 创建路由 显示视图 引入分页实现库 视图方法 创建歌手首页 增加歌手跳转 导航条改活 首页增加…

STM32H750+LAN8720无操作系统移植lwip

前言 本文提供移植好的工程&#xff0c;见本文绑定资源 环境 STM32CubeMX&#xff1a; V6.8.1 STM32H7 HAL Pack&#xff1a; V1.11.1 硬件连接 STM32H750 GPIO定义如下&#xff1a; LAN8720 GPIO定义如下&#xff1a; 连接方式如下&#xff1a; LAN8720       <—…

畅捷通T+用户中locked勒索病毒后该怎么办?勒索病毒解密数据恢复

Locked勒索病毒是一种近年来在全球范围内引起广泛关注的网络安全威胁程序。它是一种加密货币劫持病毒&#xff0c;专门用于加密用户的数据并要求其支付赎金。Locked勒索病毒通过攻击各种系统漏洞和网络薄弱环节&#xff0c;使用户计算机受到感染并被加密锁定时&#xff0c;无法…

easyexcel poi根据模板导出Excel

1.导入依赖 <!-- poi依赖--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.1</version> </dependency> <!-- poi对于excel 2007的支持依赖--> <dependency…

基于Spring Boot 的 Ext JS 应用框架之coworkee

Ext JS 官方提供了一个人员管理的完整应用框架 - coworkee。该框架的显示如下: 该框架的布局特点如下: 布局方式: 左右布局, 左侧导航栏默认收合特点:左侧导航区占用空间小, 工作区较大, 适合没有二级导航栏,工作区需要显示的内容较多的系统。如果导航栏是横向底部,就…

❤ 给自己的mac系统上安装java环境

❤ 给自己的mac系统上安装java环境 &#x1f353; 作为前端工程师如何给自己的mac系统上安装java环境 &#x1f34e; 最近因为自己的一些项目需求&#xff0c;mac电脑上需要安装一些后台的java环境&#xff0c;用来跑后台的java程序&#xff0c;于是从一个前端工程师的角度安…