当前位置: 首页 > news >正文

分布式事务解决方案——TCC

TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认Confirm、撤销Cancel。

1、Try 阶段是做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作,它和后续的Confirm一起才能真正构成一个完整的业务逻辑。

2、Confirm 阶段是做确认提交,Try阶段所有分支事务执行成功后开始执行Confirm。通常情况下,TCC认为Confirm阶段是不会出错的,若Confirm阶段真的出错了,则重试或人工处理。

3、Cancel 阶段是在业务执行错误需要回滚的状态下执行分支事务的业务取消,预留资源释放。通常情况下,TCC认为Cancel阶段也是一定成功的,若Cancel阶段真的出错了,则重试或人工处理。

TM(事务管理器)首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的Cancel操作;若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel操作若执行失败,TM会进行重试。

所有try都成功

有一个try失败

特别提醒

  1. 所有分支事务的try阶段执行成功,则会执行confirm阶段。TCC认为confirm阶段一定会执行成功,如果confirm执行失败,则会重试或者人工处理错误。

  1. 任何一个分支事务的try阶段执行失败,则会执行cancel阶段。TCC认为cancel阶段一定会执行成功,如果cancel执行失败,则会重试或者人工处理错误。

TCC需要注意三种异常处理分别是:空回滚、幂等、悬挂。

空回滚

事务管理器调用服务的try操作,可能会出现因为丢包而导致的网络超时,导致应用的try阶段没执行,事务管理器认为执行try超时,会触发cancel操作。这就导致cancel比try先执行。

悬挂

1、事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因网络拥堵而导致的超时。

2、此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,Cancel 执行正常。

3、在此之后,拥堵在网络上的一阶段 Try 数据包被 TCC 服务收到,出现了二阶段 Cancel 请求比一阶段 Try 请求先执行的情况。

4、此 TCC 服务在执行晚到的 Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel ,造成 TCC 服务悬挂。

幂等

try、confirm、cancel都会被重复调用,需要做幂等处理。

处理空回滚、悬挂、幂等

可以使用日志表,来解决 空回滚、悬挂、幂等。

新建3张表

try阶段日志表local_try_log

字段

注释

tx_no

全局事务id

create_time

创建时间

confirm阶段日志表local_confirm_log

字段

注释

tx_no

全局事务id

create_time

创建时间

cancel阶段日志表local_cancel_log

字段

注释

tx_no

全局事务id

create_time

创建时间

例子

从银行1转账10元给银行2,使用TCC方案

方案1

银行1

try:幂等校验,查找try日志(全局事务id是主键)悬挂处理,查找confirm、cancel日志(全局事务id是主键)检查余额是否够10元锁定10元插入try日志(全局事务id是主键)
confirm:幂等校验,查找confirm日志(全局事务id是主键)扣减10元删除锁定10元插入confirm日志(全局事务id是主键)
cancel:cancel幂等校验,查找cancel日志(全局事务id是主键)空回滚处理,查找try日志(全局事务id是主键)增加余额10元(回滚)删除锁定10元插入cancel日志(全局事务id是主键)

银行2

try:幂等校验,查找try日志(全局事务id是主键)悬挂处理,查找confirm、cancel日志(全局事务id是主键)插入待激活10元插入try日志(全局事务id是主键)
confirm:幂等校验,查找confirm日志(全局事务id是主键)正式增加30元删除待激活10元插入confirm日志(全局事务id是主键)
cancel:空

由于业务很简单,上面的流程还可以取消锁定,解锁的操作,直接在银行1的try中扣减10元,流程如下。

方案2

银行1

try:幂等校验,查找try日志(全局事务id是主键)悬挂处理,查找confirm、cancel日志(全局事务id是主键)检查余额是否够10元扣减10元插入try日志(全局事务id是主键)
confirm:空
cancel:cancel幂等校验,查找cancel日志(全局事务id是主键)空回滚处理,查找try日志(全局事务id是主键)增加余额10元(回滚)插入cancel日志(全局事务id是主键)

银行2

try:空
confirm:幂等校验,查找confirm日志(全局事务id是主键)正式增加30元插入confirm日志(全局事务id是主键)
cancel:空

Hmily实现方案2的代码

服务1

@Service
@Slf4j
public class Bank1ServiceImpl implements Bank1Service {@AutowiredAccountInfoDao accountInfoDao;@AutowiredHmilyLogDao hmilyLogDao;@AutowiredBank2Client bank2Client;@Override@Transactional(rollbackFor = Exception.class)@Hmily(confirmMethod = "confirm", cancelMethod = "cancel")public void updateAccountBalance(String msg, Double amount) {// 全局事务idString transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank1 try 开始,transId={}", transId);// 幂等判断int existTry = hmilyLogDao.isExistTry(transId);// 通故全局事务id查找到try日志,表明已经只执行过tryif (existTry > 0) {log.info("已经执行过try,无需重复执行try,transId={}", transId);return;}// 悬挂处理int existConfirm = hmilyLogDao.isExistConfirm(transId);int existCancel = hmilyLogDao.isExistCancel(transId);// 通故全局事务id查找到confirm、cancel日志,表明已经只执行过confirm、cancelif (existConfirm > 0 || existCancel > 0) {log.info("confirm,cancel有一个已经执行过,try不能再次执行,transId={}", transId);return;}// 制造空回滚if (StringUtils.equals("制造空回滚", msg)) {throw new RuntimeException("try方法没修改数据库就抛出异常,cancel方法会执行,形成空回滚,transId=" + transId);}// blank1减金额accountInfoDao.subtractAccountBalance("1", amount);// 添加try日志记录,try日志和扣减余额在同一个本地事务中,要么都成功,要么都失败// 日志的组件id必须是全局事务id,如果同一个事物重复调用try,到这一步会报主键重复hmilyLogDao.addTry(transId);// 远程调用Boolean result = bank2Client.transfer(msg, amount);if (!result) {throw new RuntimeException("调用bank2失败");}// bank1调用bank2成功后,发生异常,模拟回滚if (StringUtils.equals("bank1调用bank2成功后,发生异常,模拟回滚", msg)) {throw new RuntimeException("bank1调用bank2成功后,发生异常,模拟回滚,transId=" + transId);}}public void confirm(String accountNo, Double amount) {String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank1 confirm 开始执行,transId={}", transId);}@Transactional(rollbackFor = Exception.class)public void cancel(String msg, Double amount) {// 全局事务idString transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank1 cancel 开始执行,transId={}", transId);// 幂等判断int existCancel = hmilyLogDao.isExistCancel(transId);if (existCancel > 0) {log.info("cancel已经执行过,无需重复执行,transId={}", transId);return;}// 处理空回滚int existTry = hmilyLogDao.isExistTry(transId);if (existTry == 0) {log.info("try未执行过,不能执行cancel,transId={}", transId);return;}// bank1回滚,加钱accountInfoDao.addAccountBalance(msg, amount);// 添加日志hmilyLogDao.addCancel(transId);}}
@Service
@Slf4j
public class Bank2ServiceImpl implements Bank2Service {@AutowiredAccountInfoDao accountInfoDao;@AutowiredHmilyLogDao hmilyLogDao;@Override@Hmily(confirmMethod = "confirm", cancelMethod = "cancel")public void updateAccountBalance(String msg, Double amount) {String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank2 try 开始执行,transId:{}",transId);}@Transactional(rollbackFor = Exception.class)public void confirm(String msg, Double amount) {// 全局事务idString transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank2 confirm 开始执行,transId:{}",transId);int existConfirm = hmilyLogDao.isExistConfirm(transId);if (existConfirm > 0) {log.info("bank2 confirm 已经执行过,无需再次执行,transId", transId);return;}// bank2加钱accountInfoDao.addAccountBalance("2", amount);// 添加confirm日志hmilyLogDao.addConfirm(transId);// bank2 confirm,抛出异常,会重试if (StringUtils.equals("confirm抛出异常会重试", msg)) {throw new RuntimeException("confirm抛出异常会重试,transId=" + transId);}}public void cancel(String msg, Double amount) {String transId = HmilyTransactionContextLocal.getInstance().get().getTransId();log.info("bank2 cancel 开始执行,transId:{}",transId);}}

相关文章:

分布式事务解决方案——TCC

TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认Confirm、撤销Cancel。1、Try 阶段是做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作,它和后续的Confirm一起才能真正构成…...

ITSS认证分为几个级别,哪个级别最高

​一、什么是ITSS ITSS( 信息技术服务标准,简称ITSS)是国内第一套成体系和综合配套的信息技术服务标准库,全面规范了IT服务产品及其组成要素,用于指导实施标准化和可信赖的IT服务。 ITSS是在工业和信息化部、国家标准化管理委员会的联合指导下…...

ZigBee案例笔记 - USART

文章目录1.串行通信接口简述2.串行通信接口寄存器U0CSR (0x86) -USART 0 控制和状态U0UCR (0xC4)–USART 0 UART 控制U0GCR (0xC5)–USART 0 通用控制U0BUF (0xC1) – USART 0 接收/传送数据缓存U0BAUD (0xC2) – USART 0 波特率控制3.设置串行通信接口比特率控制寄存器4.外设I…...

java | 基于Redis的分布式锁实现①

前言 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性。在任意时刻,只有一个客户端能持有锁。不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户…...

十六、基于FPGA的CRC校验设计实现

1,CRC校验循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的…...

2022爱分析 · DataOps厂商全景报告 | 爱分析报告

报告编委 李喆 爱分析合伙人&首席分析师 廖耘加 爱分析分析师 目录 1. 研究范围定义 2. 市场洞察 3. 厂商全景地图 4. 市场分析与厂商评估 5. 入选厂商列表 1. 研究范围定义 研究范围 在后疫情时代,以数据分析为代表的数据消费场景日益丰富&…...

京东前端react面试题及答案

useEffect 与 useLayoutEffect 的区别 (1)共同点 运用效果: useEffect 与 useLayoutEffect 两者都是用于处理副作用,这些副作用包括改变 DOM、设置订阅、操作定时器等。在函数组件内部操作副作用是不被允许的,所以需…...

TongWeb8数据源相关问题

问题一:数据源连接不足当TongWeb数据源连接用完时,除了监控中看到连接占用高以外,日志中会有如下提示信息。2023-02-14 10:24:43 [WARN] - com.tongweb.web.jdbc.pool.PoolExhaustedException: [TW-0.0.0.0-8088-3] Timeout: Pool empty. Una…...

关于最近大热的AI,你怎么看?

AI人工智能,相信大家都不陌生,也都接触过不少。但是最近小编在网上冲浪的时候发现各大媒体又掀起了一阵AI热潮,AI不是很常见了吗?是又有什么新的发展吗? 带着强烈的好奇心,我在地铁上读完了一篇关于Chatgp…...

25.架构和软件产品线

文章目录25 Architecture and Software Product Lines架构和软件产品线25.1 An Example of Product Line Variability 产品线可变性的一个例子25.2 What Makes a Software Product Line Work? 软件产品线的工作原理是什么?25.3 Product Line Scope 产品线范围25.4 …...

Seata-server 源码学习(一)

Seata源码学习引入 学习了Seata的应用以后,我们从这开始要开始分析Seata的源码相关内容 源码下载 官方地址:https://seata.io/zh-cn/blog/download.html 通过idea打开seata-1.4.2版本的源码 回顾AT模式 其实在之前的应用课程中,我们已经用…...

2023新华为OD机试题 - 斗地主(JavaScript)

斗地主 题目 斗地主起源于湖北十堰房县, 据传是一位叫吴修全的年轻人根据当地流行的扑克玩法“跑得快”改编的, 如今已风靡整个中国,并流行于互联网上 牌型: 单顺,又称顺子,最少5张牌,最多12张牌(3...A),不能有2, 也不能有大小王,不计花色 例如:3-4-5-7-8,7-8-9-1…...

素数相关(结合回文数,合数)线性筛素数(欧拉筛法)Euler【算法模板笔记】

一、朴素筛法(埃拉托斯特尼筛法)Eratosthenes 筛法(埃拉托斯特尼筛法,简称埃氏筛法)时间复杂度是O(nloglogn)不常用,被欧拉筛代替,略二、线性筛素数(欧拉筛法)简介线性筛…...

1.7配置OSPF手动汇总

实验7:配置OSPF手动汇总 实验目的实现OSPF路由汇总的配置阐明OSPF引入的外部路由时进行路由汇总的方法实验拓扑配置OSPF手动汇总实验拓扑如图1-17所示。 图1-17 配置OSPF手动汇总 实验步骤配置IP地址,配置OSPF(和实验6一致,此处略)在…...

多线程下载工具axel的安装和使用

多线程下载工具axel的安装和使用 Axel是一个轻量级下载程序,它和其他加速器一样,对同一个文件建立多个连接,每个连接下载单独的文件片段以更快地完成下载。 Axel 支持 HTTP、HTTPS、FTP 和 FTPS 协议。它也可以使用多个镜像站点下载单个文件…...

大数据专业职业前景如何

大数据专业毕业生未来的岗位选择空间比较大,有三大类岗位可选择分别是大数据开发岗位、大数据分析岗位和大数据运维岗位,在不同的行业和技术体系结构下这些岗位也包含很多细分的岗位。 大数据开发岗位分为平台研发岗位和行业场景开发岗位两大类&#xf…...

拉格朗日乘数法在原材料选择问题上的具体应用

问题需求: 输入待制作的材料:(材料长,材料数量) 分别为(5401,124)、(200,135)、(1350,45), 输入原材料长度最大值6500,最小值3500&…...

零信任-腾讯零信任iOA介绍(4)

​腾讯零信任介绍 腾讯零信任是一种信息安全架构,旨在通过限制对计算设备、数据和应用程序的访问来保护敏感信息。腾讯零信任的主要思想是,任何计算设备、数据或应用程序都不应被自动信任,并需要经过授权后才能访问敏感信息。 腾讯零信任的…...

标准的maven依赖包应该包含哪些东西?

背景在阅读源码的时候,发现有一些maven依赖包里面没有包含pom文件,一些maven依赖包包含,而且除此之外还有一些细微的差异。今天就来聊一下关于一个标准的依赖包应该是什么样子的。一个标准的Maven依赖包通常包含以下文件:Java类文…...

网络安全-Nmap

网络安全-Nmap Nmap-号称诸神之眼 这个呢就是用来扫描网络端口的 Namp的工作原理很像一个雷达 做任何攻击之前,得先知道怎么去找破绽,而不是钢铁洪流,那个是不叫渗透了,叫硬钢。 咋用呢? 很简单 直接 nmap 后面跟网址…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)

Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...

ThreadLocal 源码

ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...

World-writable config file /etc/mysql/mysql.conf.d/my.cnf is ignored

https://stackoverflow.com/questions/53741107/mysql-in-docker-on-ubuntu-warning-world-writable-config-file-is-ignored 修改权限 -> 重启mysql # 检查字符集配置 SHOW VARIABLES WHERE Variable_name IN (character_set_server, character_set_database ); --------…...

【Docker 02】Docker 安装

🌈 一、各版本的平台支持情况 ⭐ 1. Server 版本 Server 版本的 Docker 就只有个命令行,没有界面。 Platformx86_64 / amd64arm64 / aarch64arm(32 - bit)s390xCentOs√√Debian√√√Fedora√√Raspbian√RHEL√SLES√Ubuntu√√√√Binaries√√√ …...