接着前面两篇说,下面我们继续对 Seata 的 TCC 模式进行讨论。
简单回顾一下 TCC 的原理 参考 蚂蚁金服的博客
正常事务逻辑
-
try
-
cancel 或 confirm
允许空回滚
1 未正常 try 2 执行了空 cancel
TCC 服务在未收到 Try 请求的情况下收到 Cancel 请求,这种场景被称为空回滚;空回滚在生产环境经常出现,用户在实现 TCC 服务时,应允许允许空回滚的执行,即收到空回滚时返回成功。
防悬挂控制
-
try 超时
-
cancel 成功
-
try 重试
-
Confirm 或者 Cancel 永远不会得到执行,造成悬挂。
此外,除了上面这些,和 AT 一样,还是要注意幂等的控制。
先讲下抽象流程和注意事项
-
首先定义事务接口,接口中就是你的 tcc 三个方法,对应代码中的 prepare、commit、rollback。
-
注意加@LocalTCC 注解(必要),适用于 SpringCloud+Feign 模式下的 TCC
-
@TwoPhaseBusinessAction(必要) 注解 try 方法,name 一般写方法名就行,注意全局唯一,commitMethod 对应提交方法名,rollbackMethod 对应回滚方法名。
-
BusinessActionContext 就是 seata tcc 的事务上下文,用于存放 tcc 事务的一些关键数据。BusinessActionContext 对象可以直接作为 commit 方法和 rollbakc 方法的参数,Seata 会自动注入参数:
-
@BusinessActionContextParameter 该注解用来修饰 Try 方法的入参,被修饰的入参可以在 Commit 方法和 Rollback 方法中通过 BusinessActionContext 获取
我们根据 官方的例子 用一个业务场景串一下。
这是一个转账的操作:
接口定义:
在事务调用入口加入 @GlobalTransactional
-
先让扣钱参与者准备扣钱,如果失败,则回滚本地和分布式事务 看下扣钱的 try 方法实现:
-
再让加钱参与者准备加钱,如果失败,则回滚本地和分布式事务 看下加钱的 try 方法实现:
-
如果上面两步都成功,则会分别调用各自的 commit 方法,如果方法有异常将会重试 firstAction 提交扣钱
secondAction 提交加钱
-
如果 firstAction 和 secondAction 的 try 方法有异常将会自动调用各自的 rollback 方法:
整体来看 TCC 的模式编码还是比较简单的,不过还是有几点需要注意:
-
根据业务设计好 tcc 的三个方法
-
接口幂等
-
允许空回滚 比如以订单创建举例,如果 try() 方法没执行,那么订单一定没创建,所以 cancle 方法里可以加一个判断,如果上下文中订单编号 orderNo 不存在或者订单不存在,直接 return
if(orderNo==null || order==null){ return; }
-
防悬挂控制(参考 https://blog.csdn.net/hosaos/article/details/89136666 ) 可以在二阶段执行时插入一条事务控制记录,状态为已回滚,这样当一阶段执行时,先读取该记录,如果记录存在,就认为二阶段回滚操作已经执行,不再执行 try 方法。