合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
## :-: springcloud 整合TX-LCN实现分布式事务 ## 前言 ``` SpringCloud分布式架构给我们带来开发上的便利,同时增加了我们对事务管理的难度,微服务的遍地开花,本地事务已经无法满足分布式的要求,由此分布式事务问题诞生。 分布式事务被称为世界性的难题。 ``` 本文记录整合TX-LCN分布式事务框架管理分布式事务,用的版本是5.0.2.RELEASE ## TX-LCN ### 简单介绍 TX-LCN分布式事务框架,LCN并不生产事务,LCN只是本地事务的协调工,LCN是一个高性能的分布式事务框架,兼容dubbo、springcloud框架,支持RPC框架拓展,支持各种ORM框架、NoSQL、负载均衡、事务补偿 ### 特性一览 1、一致性,通过TxManager协调控制与事务补偿机制确保数据一致性 2、易用性,仅需要在业务方法上添加@TxTransaction注解即可 3、高可用,项目模块不仅可高可用部署,事务协调器也可集群化部署 4、扩展性,支持各种RPC框架扩展,支持通讯协议与事务模式扩展 本文实现的是基于spring-cloud-alibaba整合tx-lcn实现分布式事务。 ~~~ springcloud :Hoxton.RELEASE spring-cloud-alibaba:2.2.0.RELEASE spring-boot:2.3.2.RELEASE openfeign:2.2.0.RELEASE nacos:1.0.0 ~~~ 原理 ![](https://box.kancloud.cn/caa18718890ded7863b21ab93dcc18ca_820x805.png) ## 实施步骤1 【搭建tx-manage 管理后台服务】 创建数据库、表 1. 创建MySQL数据库, 名称为:hj\_mall\_tx 2. 创建数据表:t\_tx\_exception ``` CREATE TABLE `t_tx_exception` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `transaction_state` tinyint(4) NULL DEFAULT NULL, `registrar` tinyint(4) NULL DEFAULT NULL, `remark` varchar(4096) NULL DEFAULT NULL, `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解决 1已解决', `create_time` datetime NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; ``` 下载官网提供的最新版的TM项目,修改配置文件(PS:由于官网的下载地址打不开,我们去GitHub上面下载例子:[https://github.com/codingapi/txlcn-demo](https://github.com/codingapi/txlcn-demo)),参考txlcn-demo-tm工程,在我们之前的项目下面创建一个springboot项目叫txlcn-tm **改造项目:使用远程nacos配置中心配置项目 且分为多环境 改造过程略......tx-manage项目配置文件如下** ``` spring.application.name=hmall-tx-manager server.port=9009 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://***************.mysql.rds.aliyuncs.com:3306/hj_mall_tx spring.datasource.username=**** spring.datasource.password=**** mybatis.configuration.map-underscore-to-camel-case=true mybatis.configuration.use-generated-keys=true # TxManager Host Ip tx-lcn.manager.host=127.0.0.1 # TxClient连接请求端口 tx-lcn.manager.port=9108 # 心跳检测时间(ms) tx-lcn.manager.heart-time=15000 # 分布式事务执行总时间 tx-lcn.manager.dtx-time=3000000 #参数延迟删除时间单位ms tx-lcn.message.netty.attr-delay-time=10000 tx-lcn.manager.concurrent-level=128 # TM后台登陆密码,默认值为codingapi tx-lcn.manager.admin-key=123456 logging.level.com.codingapi=debug #redis 主机 spring.redis.host=*********** #redis 端口 spring.redis.port=6379 #redis 密码 spring.redis.password=********* # 开启日志,默认为false tx-lcn.logger.enabled=true tx-lcn.logger.driver-class-name=${spring.datasource.driver-class-name} tx-lcn.logger.jdbc-url=${spring.datasource.url} tx-lcn.logger.username=${spring.datasource.username} tx-lcn.logger.password=${spring.datasource.password} #事物执行时间 ``` ``` <dependencies> <dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-tc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-tm</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--alibaba:nacos配置中心--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies> ``` ***** \*\*打包执行hmall-tx-manage.jar \*\* 浏览器打开http://127.0.0.1:9009 如下 ![](https://img.kancloud.cn/91/76/917680e2e12be4cde4d31e1a8fe0ebda_1228x547.png) ![](https://img.kancloud.cn/f4/fa/f4fa54b36b4fa8badc118d9825b80d25_1085x589.png) ## 实施步骤2【搭建2个 Tx-Client】 1、创建2Tx-Client个项目 作为事务消费者服务。 TC端参照官网一步步操作:[https://www.txlcn.org/zh-cn/docs/start.html](https://www.txlcn.org/zh-cn/docs/start.html) ![](https://img.kancloud.cn/9a/85/9a85ece71aebc4e6077555332ab75b87_263x315.png) 2、每个服务配置如下 ``` <dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-tc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-txmsg-netty</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ``` ``` server: port: 6001 spring: # --------------cloud配置------------------ cloud: nacos: discovery: server-addr: 127.0.0.1:8848 #注册服务控制中心 main: allow-bean-definition-overriding: true application: name: tx-lcn-A #------------数据库链接----------------------------- datasource: url: ${datasource.url} username: ${datasource.username} password: ${datasource.password} driver-class-name: ${datasource.driver-class-name} mybatis-plus: mapper-locations: classpath:/mapper/*Mapper.xml #实体扫描,多个package用逗号或者分号分隔 typeAliasesPackage: com.hjf.test.entity,com.hjf.base,MyOgnl configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射 map-underscore-to-camel-case: false global-config: db-config: id-type: auto datasource: url: jdbc:mysql://***********.mysql.rds.aliyuncs.com:3306/hj_mall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&zeroDateTimeBehavior=convertToNull&useSSL=false username: root password: *** driver-class-name: com.mysql.jdbc.Driver tx-lcn: client: manager-address: 127.0.0.1:9108 springcloud: loadbalance: enabled: true logger: password: ******** username: root jdbc-url: jdbc:mysql://*****************.mysql.rds.aliyuncs.com:3306/hj_mall_tx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT&zeroDateTimeBehavior=convertToNull&useSSL=false driver-class-name: com.mysql.cj.jdbc.Driver enabled: true springcloud: loadbalance: enabled: true #开启hystrix 熔断 feign: hystrix: enabled: true # --------------负载均衡器配置------------------ ribbon: ReadTimeout: 60000 ConnectTimeout: 60000 ``` 3、在启动类上使用 @EnableDistributedTransaction ~~~ //注册服务到注册中心去 @EnableDiscoveryClient @SpringBootApplication //开启分布式事务 @EnableDistributedTransaction @EnableTransactionManagement @EnableFeignClients @ServletComponentScan(basePackages = "com.hjf") public class TxLanClient1Application { public static void main(String[] args) { SpringApplication.run(TxLanClient1Application.class, args); } } ~~~ 4、流程分析 txlcn-client2 使用openfeign 调用远程txlcn-client1 添加数据库服务, 然后在执行一次添加数据库;正常情况下会添加2条数据 发生异常会回滚事务。添加0条数据。 ### **A:调用方代码** ~~~ /** * @LcnTransaction//分布式事务 * @Transactional//本地事务 */ @LcnTransaction(propagation = DTXPropagation.REQUIRED) //分布式事务注解 @Override public BaseResp addCarousel(MarketCarousel q) { String groupId = TracingContext.tracing().groupId(); String applicationId = Transactions.getApplicationId(); System.out.println(groupId); System.out.println(applicationId); marketCarouselMapper.insert(q); BaseResp r=feignService.add(q); if (StringUtils.isBlank(q.getTitle())){ throw new NullPointerException("抛出异常........"); } return BaseResp.SUCCESS; } ~~~ ### **B:远程方法调用 feign通过nacos注册中心** ~~~ /** * 远程服务名称 */ @FeignClient(name = "tx-lcn-A") public interface FeignService { @PostMapping("/cus/add") public BaseResp add(@RequestBody MarketCarousel q); } ~~~ ### **C:远程方法** ~~~ @RestController @Slf4j @RequestMapping("/cus") public class CusController { @Resource BootService bootService; @RequestMapping(value = "add") public BaseResp addCarousel(@RequestBody MarketCarousel q){ BaseResp r=bootService.addCarousel(q); return r; } } ~~~ ~~~ /** * @LcnTransaction//分布式事务 * @Transactional //本地事务 */ @LcnTransaction(propagation = DTXPropagation.SUPPORTS) @Override public BaseResp addCarousel(MarketCarousel q) { String groupId = TracingContext.tracing().groupId(); String applicationId = Transactions.getApplicationId(); System.out.println(groupId); System.out.println(applicationId); marketCarouselMapper.insert(q); return BaseResp.SUCCESS; } ~~~ ### **D:测试** 1、正常 ![](https://img.kancloud.cn/bf/3a/bf3a8411968b59c55ba4145d51e0e804_606x472.png) ![](https://img.kancloud.cn/a7/08/a708d8ec36137bec17a322d9bb3e8540_744x212.png) 2 异常:事务回滚 ![](https://img.kancloud.cn/3b/82/3b82540c6aecd52dbb2b5681b9ac9ca5_593x409.png) ![](https://img.kancloud.cn/fd/4d/fd4de377fbe793ce3aeb295bc03526ef_689x221.png) ![](https://img.kancloud.cn/97/44/9744e565a93a55586e5228df66d0f113_1225x253.png) ![](https://img.kancloud.cn/30/90/3090bdb140c52c12329ae4286d4c107a_987x506.png)