当前位置: 移动技术网 > IT编程>开发语言>Java > 荐 分布式事务-tx-lcn。

荐 分布式事务-tx-lcn。

2020年07月21日  | 移动技术网IT编程  | 我要评论

1.介绍

    LCN并不生产事务,LCN只是本地事务的协调工,LCN是一个高性能的分布式事务框架,兼容dubbo、springcloud框架,支持RPC框架拓展,支持各种ORM框架、NoSQL、负载均衡、事务补偿

    a、强一致性,通过TxManager协调控制与事务补偿机制确保数据一致性(主要特点,强一致性,比消息事务强的方面)。

    b、易用性,仅需要在业务方法上添加相应注解即可,有个简易的可视化界面。

    c、高可用,项目模块不仅可高可用部署,事务协调器也可集群化部署。

2.流程图

3.关键组件:

eureka-server:服务注册与发现。

txlcn-tm:txlcn的事务管理器,可直接用的jar包(https://download.csdn.net/download/leadseczgw01/12543652,需修改配置文件地址和端口)。

service-a:springcloud 2.1.0,服务a,操作数据库及调用服务b1。

service-b1:springcloud 2.1.0,服务b1,操作数据库。

redis

4.github代码:https://github.com/kickTec/springCloudDemo/tree/tx-lcn

5.service-a/service-b1关键依赖

        <!-- txlcn分布式事务管理 -->
        <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>

        <!--lombok插件 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

6.service-a关键代码

    @LcnTransaction//分布式事务
    @Override
    public String txlcn(String exFlag) {
        //先调用本地服务,新增一个用户user PS:调用EntityManager的merge,传进去的实体字段是什么就保存什么
        TbUser tbUser = new TbUser();
        tbUser.setUsername("tx-lcn-"+exFlag);
        tbUser.setPassword("123456");
        TbUser user = entityManager.merge(tbUser);
        System.out.println(user);

        //调用B服务,新增一个用户描述description
        TbDescription description1 = bFeign.txlcn(user.getId());
        System.out.println(description1);

        if("catchNull".equals(exFlag) && description1 == null){
            throw new RuntimeException("服务2异常!");
        }

        if("numExcepiton".equals(exFlag)){
            int num = 1/0;
        }

        //根据标识,是否抛出异常
        if (!StringUtils.isEmpty(exFlag)) {
            return "操作成功,请查看一下数据库验证!";
        } else {
            throw new RuntimeException("rollback transactional by exFlag");
        }
    }

service-b1关键代码

    @LcnTransaction//分布式事务
    @Override
    public TbDescription txlcn(Integer userId){
        TbDescription tbDescription = null;
        try{
            tbDescription = entityManager.find(TbDescription.class, userId);
            if(tbDescription == null){
                tbDescription = new TbDescription();
                tbDescription.setId(userId);
                tbDescription.setUserId(userId);
                tbDescription.setDescription("服务B设置的描述");
            }else{
                tbDescription.setDescription(tbDescription.getDescription()+",服务B设置的描述");
            }
            tbDescription = entityManager.merge(tbDescription);
            int num = 1/0;
        }catch (Exception e){
            tbDescription = null;
            System.out.println(e.getMessage());
        }
        return tbDescription;
    }

7.执行流程:

7.1 数据库文件使用https://github.com/kickTec/springCloudDemo/tree/tx-lcn中的test.sql。

7.2 依次启动eureka 、txlcn-tm、service-a、service-b1;

7.3 正常业务:调用a服务的txlcn接口,会在本地持久化一条tbuser数据(username为tx-lcn-参数);再调用b1服务的txlcn接口,新增一条tbdescription数据(userId为前面a服务持久化的userId)。

调用A服务接口:http://192.168.0.18:10081/txlcn?exFlag=kenick01

A服务打印的日志:

b1服务日志:

7.4 异常情况

a服务本地持久化成功,并且调用b服务成功,后续发送异常;调用a接口:http://192.168.0.18:10081/txlcn?exFlag=numExcepiton。

a服务日志:

b服务日志:

另一种事务异常情况:

a服务持久化数据成功,b服务持久化数据失败。在b服务的业务中增加产生异常的代码,注意:如果b服务产生的异常在controller层被捕获了(很有可能),此时A服务获取到B服务的结果,但是没捕获到异常,会造成A服务不会回滚(若B服务controller层不捕获异常,则可以回滚,这个应该机制问题,感觉后续可以优化,影响不大)。

int num = 1/0; // 抛出异常

a服务日志:

b服务日志:

评价:通过中间件tx-lcn-tm管理事务,使用代理本地数据库连接的方式,控制不同服务的事务提交和回滚,能够实现教好的强一致性;不足之处,不同服务之间会增加额外的通信开销,同时由于多个服务必须都处理完毕,事务才会提交会回滚,会锁定资源比较长时间,这点需要注意。

本文地址:https://blog.csdn.net/leadseczgw01/article/details/106918201

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网