## :-: 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)
- 项目介绍
- 项目声明
- 项目简介
- 架构设计
- 项目亮点功能介绍
- 技术栈介绍
- 核心功能
- 运行环境
- 项目更新日志
- 文档更新日志
- F&Q
- 部署教程
- 环境准备
- JDK安装
- JDK1.8,17共存
- maven
- 分布式缓存Redis
- 单机版
- 集群
- 注册&配置中心alibaba/nacos
- 介绍
- Nacos安装
- Nacos配置中心
- Nacos注册发现
- Nacos生产部署方案
- 服务监控-BootAdmin
- 基本介绍
- 如何使用
- 整合Admin-Ui
- 客户端配置
- 链路追踪
- 基本介绍
- SkyWalking-1
- Skywalking-1
- 消息队列
- Kafka
- docker安装kafka
- Linux集群
- Maven私服
- nexus安装部署
- nexus使用介绍
- 全文搜索elasticsearch
- windows集群搭建
- docker安装es
- ElasticHD
- linux集群部署
- 统一日志解决方案
- 日志解决方案设计
- 介绍与相关资料
- ELK安装部署
- elasticsearch 7.5
- logstash-7.5
- kibana-7.5
- filebeat
- 服务监控-Prometheus
- Prometheus安装配置
- Prometheus介绍
- grafana
- 持续集成部署CICD
- 自动化部署Jenkins
- 安装部署win
- 打包发布远程执行
- 安装部署linux
- jenkins+gitlab+docker容器化工程自动化部署
- Git
- CICD说明
- 阿里云效
- CentOS_MYSQL安装
- docker
- 安装
- Docker安装Nginx
- Docker部署启动springboot
- dockerCompose
- harbor
- Docker私有镜像仓库
- Portainer
- Docker远程连接设置
- 打包工程
- 必要启动模块
- 核心模块
- 登录认证
- 缓存功能
- 日志模块
- 分布式锁
- 消息队列
- 异常处理
- 系统接口
- 参数验证
- es检索
- 数据导出
- 系统设计
- 系统总体架构
- 扩展模块(可选)
- 限流熔断alibaba/sentinel
- 使用Sentinel实现gateway网关及服务接口限流
- Sentinel使用Nacos存储规则及同步
- 服务调用Feign
- Feign基本介绍
- 如何使用
- 负载均衡
- 请求超时
- 请求拦截器
- 分布式任务调度
- XXL-JOB
- 分布式事务
- TX-LCN
- Seata
- Seata原理解析
- 数据库分库分表
- swagger文档
- 分布式ID生成器解决方案
- 服务网关CloudGateway
- 基本介绍
- 使用网关
- 路由配置
- 全局过滤器
- 服务认证授权架构设计
- 认证服务流程
- 授权服务流程
- 系统幂等性设计与实践
- 分布式日志链路跟踪
- 实时搜索系统设计
- 应用性能
- 压力测试工具
- Apache JMeter介绍和安装
- ApacheJMeter使用
- JVM
- JVM性能调优
- 常见JVM内存错误及解决方案
- JVM 分析工具详解
- Spring Cloud性能调优
- Linux运维
- Linux 常用命令
- Linux开启端口