seata TCC模式和AT模式的基础环境是一样的,只是在实现方式上有所区别,而且TCC模式还可以和AT模式混合使用。

关于AT模式示例,可以参考seata 1.4.2 分布式事务AT模式示例。

TCC模式的优势是灵活性,不依赖于数据库的事务特性来实现两阶段提交,而是采用代码来实现。对于无法完全依赖于数据库事务特性的分布式事务,就可以考虑使用TCC模式。、

当然TCC模式的灵活性,也就带来了复杂性,因为不能依赖于数据库事务的提交和回滚机制,就需要在代码中,针对每个需要实现分布式事务特性的业务操作,添加提交和回滚处理。

1. TCC模式代码实现

1.1 TCC接口定义

这里以一个业务为例说明,其它业务参考该模式实现即可。

package com.platform.account.tcc.service;import com.platform.account.domain.Account;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;@LocalTCC
public interface AccountTccService {/*** Prepare boolean.** @param actionContext the action context* @param account             the account* @param price             the price* @return the boolean*/@TwoPhaseBusinessAction(name = "AccountTccService", commitMethod = "commit", rollbackMethod = "rollback")public boolean prepare(BusinessActionContext actionContext,@BusinessActionContextParameter(paramName = "account") Account account,@BusinessActionContextParameter(paramName = "price") Double price);/*** Commit boolean.** @param actionContext the action context* @return the boolean*/public boolean commit(BusinessActionContext actionContext);/*** Rollback boolean.** @param actionContext the action context* @return the boolean*/public boolean rollback(BusinessActionContext actionContext);
}

接口需要增加一个注解@LocalTCC,接口定义了三个方法,其中prepare是第一阶段提交,commit和rollback是第二阶段提交。

1.2 TCC接口实现

package com.platform.account.tcc.service.impl;import com.platform.account.domain.Account;
import com.platform.account.service.AccountService;
import com.platform.account.tcc.service.AccountTccService;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.HashMap;@Service
public class AccountTccServiceImpl implements AccountTccService {@Autowiredprivate AccountService accountService;@Overridepublic boolean prepare(BusinessActionContext actionContext, Account account, Double price) {String xid = actionContext.getXid();System.out.println("TccActionOne prepare, xid:" + xid +  ", account:" + account);int res = accountService.reduceBalance(account.getId(), price);if(res > 0){return true;}else {return  false;}}@Overridepublic boolean commit(BusinessActionContext actionContext) {String xid = actionContext.getXid();System.out.println("TccActionOne commit, xid:" + xid + ", account:" + actionContext.getActionContext("account"));return true;}@Overridepublic boolean rollback(BusinessActionContext actionContext) {String xid = actionContext.getXid();System.out.println("TccActionOne rollback, xid:" + xid + ", account:" + actionContext.getActionContext("account"));// ResultHolder.setActionOneResult(xid, "R");return true;}
}

1.3 TCC接口的调用

package com.platform.account.controller;import com.platform.account.domain.Account;
import com.platform.account.handler.AjaxResult;
import com.platform.account.service.AccountService;
import com.platform.account.tcc.service.AccountTccService;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;@RestController
public class AccountController {@Autowiredprivate AccountTccService accountTccService;/*** 扣减库存接口* @param userId* @param price*/@PostMapping("/reduceBalance")AjaxResult reduceBalance(@RequestParam("userId") Long userId, @RequestParam("price")Double price){BusinessActionContext actionContext = new BusinessActionContext();Account account = new Account();account.setId(userId);System.out.println("price = " + price);        boolean res = accountTccService.prepare(actionContext, account, price);return AjaxResult.success(1);}}

2. TCC模式的异常处理

因为TCC模式需要在代码中处理各种异常,所以需要将各种情况考虑全面,因为在分布式环境中,出现网络超时、重发,机器宕机等一系列的异常,一旦这些异常情况没有处理,或者处理不合理,就可能导致业务数据错误。最常见的主要是这三种异常,分别是空回滚、幂等、悬挂。

2.1 空回滚

首先是空回滚。什么是空回滚?空回滚就是对于一个分布式事务,在没有调用 TCC 资源 Try 方法的情况下,调用了二阶段的 Cancel 方法,Cancel 方法需要识别出这是一个空回滚,然后直接返回成功。

3.2 幂等

接下来是幂等。幂等就是对于同一个分布式事务的同一个分支事务,重复去调用该分支事务的第二阶段接口,因此,要求 TCC 的二阶段 Confirm 和 Cancel 接口保证幂等,不会重复使用或者释放资源。如果幂等控制没有做好,很有可能导致资损等严重问题。

3.3 悬挂

最后是防悬挂。按照惯例,咱们来先讲讲什么是悬挂。悬挂就是对于一个分布式事务,其二阶段 Cancel 接口比 Try 接口先执行。因为允许空回滚的原因,Cancel 接口认为 Try 接口没执行,空回滚直接返回成功,对于 Seata 框架来说,认为分布式事务的二阶段接口已经执行成功,整个分布式事务就结束了。但是这之后 Try 方法才真正开始执行,预留业务资源,前面提到事务并发控制的业务加锁,对于一个 Try 方法预留的业务资源,只有该分布式事务才能使用,然而 Seata 框架认为该分布式事务已经结束,也就是说,当出现这种情况时,该分布式事务第一阶段预留的业务资源就再也没有人能够处理了,对于这种情况,我们就称为悬挂,即业务资源预留后没法继续处理。

3. 异常控制实现

在分析完空回滚、幂等、悬挂等异常 Case 的成因以及解决方案以后,下面我们就综合起来考虑,一个 TCC 接口如何完整的解决这三个问题。

首先是 Try 方法。结合前面讲到空回滚和悬挂异常,Try 方法主要需要考虑两个问题,一个是 Try 方法需要能够告诉二阶段接口,已经预留业务资源成功。第二个是需要检查第二阶段是否已经执行完成,如果已完成,则不再执行。因此,Try 方法的逻辑可以如图所示:

先插入事务控制表记录,如果插入成功,说明第二阶段还没有执行,可以继续执行第一阶段。如果插入失败,则说明第二阶段已经执行或正在执行,则抛出异常,终止即可。

接下来是 Confirm 方法。因为 Confirm 方法不允许空回滚,也就是说,Confirm 方法一定要在 Try 方法之后执行。因此,Confirm 方法只需要关注重复提交的问题。可以先锁定事务记录,如果事务记录为空,则说明是一个空提交,不允许,终止执行。如果事务记录不为空,则继续检查状态是否为初始化,如果是,则说明一阶段正确执行,那二阶段正常执行即可。如果状态是已提交,则认为是重复提交,直接返回成功即可;如果状态是已回滚,也是一个异常,一个已回滚的事务,不能重新提交,需要能够拦截到这种异常情况,并报警。

最后是 Cancel 方法。因为 Cancel 方法允许空回滚,并且要在先执行的情况下,让 Try 方法感知到 Cancel 已经执行,所以和 Confirm 方法略有不同。首先依然是锁定事务记录。如果事务记录为空,则认为 Try 方法还没执行,即是空回滚。空回滚的情况下,应该先插入一条事务记录,确保后续的 Try 方法不会再执行。如果插入成功,则说明 Try 方法还没有执行,空回滚继续执行。如果插入失败,则认为 Try 方法正再执行,等待 TC 的重试即可。如果一开始读取事务记录不为空,则说明 Try 方法已经执行完毕,再检查状态是否为初始化,如果是,则还没有执行过其他二阶段方法,正常执行 Cancel 逻辑。如果状态为已回滚,则说明这是重复调用,允许幂等,直接返回成功即可。如果状态为已提交,则同样是一个异常,一个已提交的事务,不能再次回滚。

4. 总结

通过上述的说明,可以看出TCC模式还是比较复杂的,该模式需要对业务规则有清晰和明确的定义,只有在业务规则清楚的情况下,针对各种异常情况进行全面的处理,才能确保TCC模式下的分布式事务的正确性和完整性。

示例中只是演示了TCC模式的接口实现,并没有对各种异常信息进行处理,主要是异常处理与业务特点和规则是密切关联的。有了原则性的方向,再结合业务特点,使用TCC模式实现分布式业务处理,应该说,还是具有较高可行性的。

参考代码下载

微服务seata 1.4.2 分布式事务TCC模式示例相关推荐

  1. .Net Core with 微服务 - 可靠消息最终一致性分布式事务

    前面我们讲了分布式事务的2PC.3PCTCC 的原理.这些事务其实都在尽力的模拟数据库的事务,我们可以简单的认为他们是一个同步行的事务.特别是 2PC,3PC 他们完全利用数据库的事务能力,在一阶段开 ...

  2. Seata多微服务互相调用_全局分布式事务使用案例_seata之原理剖析---微服务升级_SpringCloud Alibaba工作笔记0066

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 通过上面的案例,我们已经可以会使用seata进行全局的分布式事物的使用了,在多微服务相互调用的环境 ...

  3. SpringCloud Alibaba 微服务架构(十一)- 分布式事务解决方案及理论基础篇

    前言 在传统的单体应用架构中,例如经典的SSM,项目会采用分层架构模式:数据库访问层.业务逻辑层.控制层,从前端到后台所有的代码都是一个或者几个开发者去完成,该架构模式没有对我们业务逻辑代码实现拆分. ...

  4. dubbo调用超时回滚_微服务痛点基于Dubbo + Seata的分布式事务(AT模式)

    前言 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案. ...

  5. 探秘蚂蚁金服分布式事务 Seata 的AT、Saga和TCC模式

    作者| 屹远(陈龙),蚂蚁金服分布式事务核心研发 . 导语 本文根据 SOFA Meetup#3 广州站 <分布式事务 Seata 及其三种模式详解>主题分享整理,着重分享分布式事务产生的 ...

  6. 秒杀项目之网关服务限流熔断降级分布式事务

    目录 一.网关服务限流熔断降级 二.Seata--分布式事务 2.1 分布式事务基础 2.1.1 事务 2.1.2 本地事务 2.1.3 分布式事务 2.1.4 分布式事务场景 2.2 分布式事务解决 ...

  7. 多个mapper的事务回滚_揭秘蚂蚁金服分布式事务 Seata 的AT、Saga和TCC模式

    作者| 屹远(陈龙),蚂蚁金服分布式事务核心研发 . 导语 本文根据 8月11日 SOFA Meetup#3 广州站 <分布式事务 Seata 及其三种模式详解>主题分享整理,着重分享分布 ...

  8. python 微服务架构实战_《分布式服务架构:原理、设计与实战》第一章分布式微服务架构设计原理...

    1.从传统单体架构到服务化架构 1.1 JEE架构 JEE将企业级软件架构分为三个层级 : Web 层.业务逻辑层和数据存取层.对应的职能团队,主要包括:用户 交互 UI 团队.后台业务逻辑处理团 队 ...

  9. ShardingSphere RAW JDBC 分布式事务XA 代码示例

    ShardingSphere RAW JDBC 分布式事务XA 代码示例 项目工程在:transaction-2pc-xa-raw-jdbc-example 代码简介     基于ShardingSp ...

最新文章

  1. 百度推出LinearDesign,全球首个mRNA疫苗不稳定性解决方案,仅需16分钟
  2. 容器生态系统 (续) - 每天5分钟玩转容器技术(3)
  3. [leetcode]102.二叉树的层序遍历
  4. 深入了解计算机网络参考模型
  5. c/s三层结构信息系统的三个层次_网络资讯:三层架构是什么
  6. 解放计算给服务带来的压力,第一想到的就是阿里云高性能计算(HPC)
  7. Ubuntu18.04配置TeXLive2020+TeXstudio
  8. 大道至简 7、8、读后感
  9. vue中父子组件先后渲染_Vue中父子组件执行的先后顺序
  10. 腾讯校园招聘笔试 2019-8-17 第五题
  11. linux常用知识命令
  12. Eigen3卸载与安装
  13. 为何你的网络爬虫技术提升缓慢?甚至小白无从下手学习?
  14. Python引力波火了 你该了解的开源框架
  15. 夏昕.深入浅出Hibernate中的第一个例子体会.
  16. 微信小程序实时音视频功能简析(live-pusher与live-player)
  17. 防止跨站攻击——CSRFToken
  18. jconsole是否可以在生产环境使用_使用JCONSOLE远程监控JVM
  19. matlab整流仿真,基于MATLAB的整流电路的建模与仿真
  20. RF- BuiltIn_Run Keyword关键字系列

热门文章

  1. QQ名片赞数量查询工具 易语言源码
  2. MSP430的升级引导程序编写以及升级固件制作
  3. Cisco交换机基础命令
  4. datatables html定义,DataTables表格插件使用说明
  5. vivo 实时计算平台建设实践
  6. 如何使用HtmlUnit 抓取网页中手机版模式?
  7. CSS学习笔记之选择器(一)
  8. 小米澎湃S2流片失败,根本原因是没有顶级高手
  9. 【生活随笔】Introspection of my life in 2014
  10. 河南工业大学专升本信息安全概念(专升本)考题解析