实战!阿里神器 Seata 实现 TCC模式 解决分布式事务,真香(四)
3、悬挂
事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因网络拥堵而导致的超时,此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,Cancel 调用未超时;
在此之后,拥堵在网络上的一阶段 Try 数据包被 TCC 服务收到,出现了二阶段 Cancel 请求比一阶段 Try 请求先执行的情况,此 TCC 服务在执行晚到的 Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel ,造成 TCC 服务悬挂。
解决方案:
解决逻辑很简单:在执行try方法操作资源之前判断cancel方法是否已经执行;同样的在cancel方法执行后要记录执行的状态。
4、总结
针对以上三个异常,落地的解决方案很多,比如维护一个事务状态表,每个事务的执行阶段全部记录下来。
- 幂等:在执行confirm或者cancel之前根据事务状态表查询当前全局事务是否已经执行过confirm或者cancel方法
- 空回滚:在执行cancel之前才能根据事务状态表查询当前全局事务是否已经执行成功try方法
- 悬挂:在执行try方法之前,根据事务状态表查询当前全局事务是否已经执行过cancel方法
Seata整合TCC实现
关于如何搭建项目、添加依赖这里就不再细说了,不熟悉的可以看我之前的文章:对比7种分布式事务方案,还是偏爱阿里开源的Seata,真香!(原理+实战)
本节只介绍关键代码,毕竟篇幅有限,其他部分请自行下载源码。
“案例源码已上传GitHub,关注公众号:码猿技术专栏,回复关键:9531 获取!”
源码目录如下:
源码目录
项目启动所需要的相关文件如下图:
nacos目录中的SEATA_GROUP是Seata事务服务端和客户端所需要的相关配置,直接导入nacos即可。
seata目录中的conf是1.3.0版本服务端的配置
SQL目录是相关的几个数据库。
1、TCC接口定义
在order-boot模块创建OrderTccService,代码如下:
代码中注释已经很完整了,下面挑几个重点介绍一下:
- @LocalTCC:该注解开启TCC事务
- @TwoPhaseBusinessAction:该注解标注在try方法上,其中的三个属性如下:
a.name:TCC事务的名称,必须是唯一的
b.commitMethod:confirm方法的名称,默认是commit
c.rollbackMethod:cancel方法的名称,,默认是rollback - confirm和cancel的返回值尤为重要,返回false则会不断的重试。
2、TCC接口实现
定义有了,总要实现,如下:
1、try方法
try方法
①处的代码是为了防止悬挂异常,从事务日志表中获取全局事务ID的状态,如果是cancel状态则不执行。
②处的代码冻结库存
③处的代码生成订单,状态为待确认
④处的代码向幂等工具类中添加一个标记,key为当前类和全局事务ID,value为当前时间戳。
“注意:必须要开启本地事务,如上代码使用@Transactional开启本地事务”
文章转自公众号:码猿技术专栏