Lock(锁定事务单元)、Confirm(确认事务)、Notify(通知事务)
TX-LCN定位于一款事务协调性框架,框架其本身并不操作事务,而是基于对事务的协调从而达到事务一致性的效果。
TM:事务管理器
TC:事务客户端,相当于RM(资源管理器)
核心步骤
- 创建事务组
是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。
- 加入事务组
添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息通知给TxManager的操作。
- 通知事务组
是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager,TxManager将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方。
调用链路中的TC通过拦截器获取请求头中的事务组id,封装到TracingContext中,当封装创建TxContext时,会从TracingContext中取出事务id,用于跟TM交互
LCN事务模式
原理
当本地事务提交回滚或者关闭连接时将会执行假操作(没有真正释放连接),该代理的连接将交由TM的LCN连接池管理,在全部TC响应结果后,TM异步通知TC们“提交”或者“回滚”。
- 该模式下的事务提交与回滚是由本地事务方控制,对于数据一致性上有较高的保障。
- 该模式缺陷在于代理的连接需要随事务发起方一共释放连接,增加了连接占用的时间。
TM-TxManager(事务管理器)
集群模式下,直接启动多台TM
sql
数据库脚本位于txlcn-tm-5.0.2.RELEASE.jar包下的tx-manager.sql
1 2 3 4 5 6 7 8 9 10 11 12
| 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, `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 待处理 1已处理', `remark` varchar(10240) NULL DEFAULT NULL COMMENT '备注', `create_time` datetime(0) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 967 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
|
pom
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-tm</artifactId> <version>5.0.2.RELEASE</version> </dependency>
<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>
|
properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| server.port=7970
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/tx-manager?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root
spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.database=0
spring.application.name=tx-lcn-transaction-manager
tx-lcn.manager.admin-key=msb
tx-lcn.logger.enabled=true
tx-lcn.logger.driver-class-name=com.mysql.cj.jdbc.Driver tx-lcn.logger.jdbc-url=jdbc:mysql://localhost:3306/tx-manager?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai tx-lcn.logger.username=root tx-lcn.logger.password=root
|
java
启动类
1
| @EnableTransactionManagerServer
|
TC-TxClient(相当于RM资源管理器)
pom
1 2 3 4 5 6 7 8 9 10 11 12
| <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>
|
yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| server: port: 8083 spring: application: name: tx-lcn-order datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/tx_order?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: root password: 123
mybatis-plus: mapper-locations: classpath*:/mapper/*Mapper.xml configuration: map-underscore-to-camel-case: true
eureka: client: service-url: defaultZone: http://127.0.0.1:8081/eureka fetch-registry: true register-with-eureka: true
tx-lcn: client: manager-address: 127.0.0.1:8070
|
java
启动类
1
| @EnableDistributedTransaction
|
业务类
TCC事务模式
原理
TCC事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。
TM
上同
TC
java
启动类
1
| @EnableDistributedTransaction
|
业务类,添加@TccTransaction
注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
@GetMapping("/order/{orderName}") @Transaction @TccTransaction public String order(@PathVariable String orderName) { TxOrder order = new TxOrder(); order.setOrderName("tcc-order:" + orderName); orderService.save(order); log.info("tcc-order新增成功"); String payResult = restTemplate.getForObject("http://tx-lcn-pay/tcc/pay/" + orderName, String.class); log.info("tcc-payResult ==>" + payResult); return "tcc-order新增成功"; }
public String confirmOrder(String orderName) { System.out.println("order confirm "); return "新增订单成功-confirm"; }
public String cancelOrder(String orderName) { System.out.println("order cancel "); Map<String, Object> columnMap = new HashMap<>(); columnMap.put("order_name", "tcc-order:" + orderName); orderService.removeByMap(columnMap); return "新增订单成功-cancel"; }
|