分布式事务 —— TxLnc

简介

TX-LCN 主要有两个模块,Tx-Client(TC) Tx-Manager™. TC作为微服务下的依赖,TM是独立的服务(用于管理事务)。

前言

在这里插入图片描述
上述图片中包含两个事务,rpc事务(1.1.1 addMoney)与事务(1.1.4 create),在Start函数上有@Transactional注解,但它无法控制rpc事务,如果rpc事务出现问题,1.1.4依然会执行,所以我们就需要对分布式事务一致性进行处理

  • 函数代码如下
@Transactional
public String start(int money) {
    String user = "xiaoming";
    //此处调用Feign(RPC事务)
    String status = bankBClient.addMoney(money, user);
    if("success".equals(status)) {
        Account account = new Account();
        account.setMoney(money);
        account.setUser(user);
        //如果有错误,本地回滚,调用的feign无法回滚
        int res = accountDao.update(account);
        return res > 0 ? "success" : "error";
    }
    return "rpc error";
}

搭建环境

安装Tx-Manager

Tx-Manager(TM —— 事务管理端)

  • 下载源码
git clone https://github.com/codingapi/tx-lcn.git
  • 修改tm配置(properties)
spring.application.name=tx-manager
server.port=7970

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tx-manager?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.use-generated-keys=true

#tx-lcn.logger.enabled=true
# TxManager Host Ip
#tx-lcn.manager.host=127.0.0.1
# TxClient连接请求端口
#tx-lcn.manager.port=8070
# 心跳检测时间(ms)
#tx-lcn.manager.heart-time=15000
# 分布式事务执行总时间
#tx-lcn.manager.dtx-time=30000
#参数延迟删除时间单位ms
#tx-lcn.message.netty.attr-delay-time=10000
#tx-lcn.manager.concurrent-level=128
# 开启日志
#tx-lcn.logger.enabled=true
#logging.level.com.codingapi=debug
#redisIp
spring.redis.host=127.0.0.1
#redis端口
spring.redis.port=6379
#redis密码
spring.redis.password=123456

在使用时,按照自己的配置修改(比如我Redis有密码就要设置下)

  • 编译(txlcn-tm下)
mvn clean package '-Dmaven.test.skip=true'
  • 启动
java -jar txlcn-tm-5.0.1.RELEASE.jar
  • 访问 http://127.0.0.1:7970,并登陆默认密码是:condingapi
    在这里插入图片描述
    Tx-Client(TC) 在实际开发中才会使用,通过maven,导入依赖,具体下面的实战会介绍。

实战

TxLnc支持4种事务

  • @TxcTransaction

  • @TccTransaction

  • @TxTransaction

  • @LcnTransaction

使用LcnTransaction

创建数据库

模拟分布式事务,需要多个库

  • 创建两个库(bank-a、bank-b),并且都要执行下面的sql。
创建数据并插入一条记录
CREATE TABLE t_bank(
  id BIGINT(20) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  money INT(10) DEFAULT NULL ,
  user VARCHAR(32) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
insert into t_bank(money,user) values(1000, 'xiaoming');

此时,bank-a和bank-b库都有一条相同的数据,通过GitHub导出下面项目,并根据README进行布署。

项目
工程端口描述
bank-a8090先rpc调用bank-b服务,执行加money,然后回到bank-a执行减money
bank-b8099执行加money操作
bank-common工具类,导入tc,供bank-a、bank-b使用
关键知识点
  • 导入tc(bank-common)
<dependencies>
    <!-- 加入分布式事务基础依赖 -->
    <dependency>
        <groupId>com.codingapi.txlcn</groupId>
        <artifactId>txlcn-tc</artifactId>
        <version>5.0.1.RELEASE</version>
    </dependency>

    <!-- 加入分布式事务基础依赖 -->
    <dependency>
        <groupId>com.codingapi.txlcn</groupId>
        <artifactId>txlcn-txmsg-netty</artifactId>
        <version>5.0.1.RELEASE</version>
    </dependency>
</dependencies>
  • 在bank-a、bank-b的启动类上添加注释(标记为分布式事务管理),如下bank-a启动类
...
@EnableDistributedTransaction
public class BankAApplication {
    public static void main(String[] args) {
        SpringApplication.run(BankAApplication.class, args);
    }
}
  • 具体实现上添加@LcnTransaction注解,如下bank-a/…/BankService.java
@LcnTransaction
@Transactional
public String start(int money) {

    String user = "xiaoming";
    //此处调用Feign
    String status = bankBClient.addMoney(money, user);
    if("success".equals(status)) {
        Account account = new Account();
        account.setMoney(money);
        account.setUser(user);
        //如果有错误,本地回滚,调用的feign无法回滚
        int res = accountDao.update(account);
        throw new RuntimeException("insert money error");
//            return res > 0 ? "success" : "error";
    }
    return "rpc error";
}

当bank-a抛出异常时,rpc bank-b事务没有提交。

使用Spring Cloud Feign 熔断Hystrix获取到RPC Service错误信息后,再去调用另一个RPC Service的事务无法控制,即无法实现控制分布式事务的需求。
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐