TxManager是LCN分布式事务框架的事务协调器,框架基于Netty做消息通讯,事务控制数据存储在redis中。
TxManager采用高可用集群化部署方案,多个TM通过eureka集群完成服务注册,各个TxClient通过服务名称向TxManager发送事务信息。
一、搭建TxManager
1、创建一个springboot项目
继承父项目
<parent> <groupId>com.zl.stock</groupId> <artifactId>stock-parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../stock-parent/pom.xml</relativePath> </parent>
导入相关依赖
<!--添加Eureka-client的依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- tx-lcn的事务协调器依赖 --> <dependency> <groupId>com.codingapi.txlcn</groupId> <artifactId>txlcn-tm</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--目前只支持mysql记录日志--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
2、在启动类上添加注解,@EnableTransactionManagerServer
@SpringBootApplication @EnableTransactionManagerServer @EnableEurekaClient public class StockTxmanagerApplication {。。}
4、保留默认配置文件application.properties(无内容)
新建一个application.yml文件进行配置
3、配置yml配置文件
#配置端口
server:
port: 8521
#redis相关配置 spring: profiles: active: dev redis: host: 127.0.0.1 port: 6381 application: name: stock-txManager datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/tx-manager?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: root password: 123456 jpa: database-platform: org.hibernate.dialect.MySQL5InnoDBDialect # 数据库方言 hibernate.ddl-auto: update #第一次运行可以设置为: create, 为TM创建持久化数据库表 #eureka相关配置 eureka: instance: hostname: 127.0.0.1 #修改eureka-client在注册中心页面显示的名字 #${spring.cloud.client.ipaddress} 获取服务的ip地址 instance-id: stock-txManager-${spring.cloud.client.ipaddress}-${server.port} #服务信息显示的真实的ip, 开发中一定要设置为true, 如果不设置, 其他电脑访问不到你的服务 prefer-ip-address: true client: serviceUrl: defaultZone: http://${eureka.instance.hostname}:10001/eureka/ tx-lcn: manager: host: 127.0.0.1 # tx-manager ip(client请求ip) port: 8070 # client 请求端口 heart-time: 12000 # 心跳检测时间 单位:ms dtx-time: 3000 # 事务执行总时间 admin-key: 123456 #TM后台登陆密码,默认密码是codingapi logger: enabled: true #开启日志,默认为false,开发阶段最好开启日志,并设置为debug等级,这样方便追踪排查问题 #日志记录表 t_logger driver-class-name: ${spring.datasource.driver-class-name} jdbc-url: ${spring.datasource.url} username: ${spring.datasource.username} password: ${spring.datasource.password} logging: level: com: codingapi: txlcn: DEBUG #日志输出级别
创建成启动Eureka , 在启动TxManager服务 (默认端口为7970)
启动成功访问:http://127.0.0.1:7970/ (默认密码为codingapi,修改的密码为123456)
二、创建mysql数据库、表来保存日志
1、创建MySQL数据库, 名称为:tx-manager
2、创建数据表:创建异常记录表, 根据tx-lcn的TxException类来创建,表名为: 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;
三、搭建tx-client,就是需要用到的服务(1、调用者、2、被调用者)
1、在业务服务项目添加相关依赖
<!-- tx-lcn的client相关依赖 --> <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>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
2、启动类添加 @EnableDistributedTransaction。
//本地事务 @EnableTransactionManagement //分布式事务 @EnableDistributedTransaction
3、添加yml配置文件
tx-lcn: ribbon: loadbalancer: dtx: enabled: true # 默认之配置为TM的本机默认端口 client: manager-address: 127.0.0.1:8070 # 开启日志,默认为false logger: enabled: true driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://localhost:3306/tx-manager?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: root password: 123456
4、在用到事务的service中添加注解(需要添加两个服务我们命名为A、B关系(A调用B))
A中需要事务的地方添加
@LcnTransaction(分布式事务)
@Transactional(本地事务)
在B中需要事务的地方添加
@LcnTransaction
@Transactional
测试
A服务调用B服务
1、在A服务的ServletImpl中:
//给审核开户信息手动分配一个账号(账号使用时间戳获取)TODO 加上分布式事务 @Override @LcnTransaction//分布式事务 @Transactional//本地事务 public boolean byCard(T_realuser realuser) throws Exception { //随机生成一个十位的账号 String id = String.valueOf(Long.parseLong(String.valueOf(System.currentTimeMillis()) .substring(1,10).concat(String.valueOf(0)))); // String timer = new Date().getTime()+""; realuser.setAccountid(id); realuser.setUpdatetime(new Date()); //修改user表中的激活状态 ** (B服务中的方法) userClientService.updateUserStatus(realuser.getRusid()); return getBaseMapper().updateById(realuser) >0 ?true :false; }
2、在B服务被调用的ServletImpl中:
//审核通过将状态列改为1 @Override @LcnTransaction//分布式事务 @Transactional//本地事务 public boolean updateUserStatus(T_user user) throws Exception { //修改时间 user.setUpdatetime(new Date()); //修改状态 user.setStatus(1); //自定义异常,测试分布式事务是否成功 -- 查看是否回滚 int a = 10/0; return getBaseMapper().updateById(user) >0 ?true :false; }
3、执行方法
报错,查看数据库是否更改数据
数据库中:两张表的数据库都没有进行更改
4、查看mysql错误日志
5、也可以在TxManager系统后台中查看错误日志