十、Seata的TCC模式

10.1 什么是TCC?

1、TCC的基本理解

TCC是三个单词的缩写(try-confirm-cancel) TCC分布式事务最核⼼的思想就是在应⽤层(可以理解为我们编码)将⼀个完整的事务分为3个阶段,Try阶段、Confirm确认阶段、Cancel取消阶段

TCC虽然也是基于两阶段提交协议,但是和AT的两阶段提交协议不同,AT的两阶段提交我们只关注业务逻辑的编写,提交还是回滚都是通过undo_log实现,⽽TCC的业务逻辑,提交逻辑,回滚逻辑都由⾃⼰完成

2、三个阶段详解

  • try 阶段
    严格意义上 try阶段不会做任何业务逻辑,仅仅做业务的⼀致性检查和做相应资源的预留
    1:完成所有业务的检查 确保数据的⼀致性
    2:预留必要的业务资源,确保数据的隔离性

  • confirm阶段
    当分⽀的所有的try阶段都执⾏完成之后,开始执⾏confirm阶段,通常情况下 如果采⽤了TCC⽅案解决事务时都会认为confirm阶段是不会出错的,换句话说 只要try阶段执⾏成功了 confirm阶段⼀定会成功,如果confirm真的出错了,要提供重试机制或者⼈⼯⼲预 并且在confirm阶段不会做任何的业务检查 直接操作try阶段预留的业务资源

  • cancel阶段
    当try阶段执⾏时出现异常或执⾏错误的情况下,此时需要执⾏回滚操作, 此时就会执⾏cancel⽅法,在cancel的⽅法中释放try阶段预留的资源,和confirm阶段⼀样 如果try阶段执⾏成功,⼀般我们都会认为cancel也会成功,如果真的失败了 此时需要⼈⼯介⼊或者提供重试机制

10.2 TCC模式的原理流程图

在这里插入图片描述

10.3 TCC解决多数据源问题

1、环境搭建

见 gitee : https://gitee.com/houchen1996/seata-shangma 的模块 tcc-multidatasource-demo

2、TCC模式解决分布式事务问题

1) 添加 Seata 依赖
2)添加Seata配置
3)编写方法,定义 commit 操作,和canel操作
4)使用注解 @LocalTCC和@TwoPhaseBusinessAction(name = “jian”, commitMethod = “commit”, rollbackMethod = “cancel”)
5)使用 @GlobalTransactional 注解

测试 : 请求 http://localhost:8080/user/transfer?fromId=1&toId=1&monoey=100
在这里插入图片描述

【注意】TCC虽然没有undo_log表,但是在预留资源的时候还需要列的支持

10.4 TCC⾯临的问题 - 2、空回滚问题

1、什么空回滚?

空回滚表示 在⼀次事务中 并没有执⾏try⽅法,直接执⾏了rollback进⾏了回滚从⽽导致数据错误

举例子: 张三给李四赚钱5000, 执⾏了张三的try⽅法,由于钱不够,并没有执⾏转钱锁定资源 ⽽是直接⾛了rollback⽅法

2、举例

还是上面的工程, 在转账操作中加上如果转账金额大于账户金额,抛出异常的逻辑

 @Override
    public void reduceMoney(BusinessActionContext context, int userId, double money) {
        Double moneyById = nongUserMapper.findMoneyById(userId);
        if (moneyById < money) {
            throw new RuntimeException("余额不足");
        }
        nongUserMapper.reduceMoney(userId, money);
    }

请求: http://localhost:8080/user/transfer?fromId=1&toId=1&monoey=5000
查看结果
在这里插入图片描述

3、空回滚解决

10.5 TCC⾯临的问题 - 1、幂等性问题

1、幂等性问题

如果服务器⽹络异常 或者⽹络延迟等等,导致超时 ⼀般的TCC管理器都会有重试机制,因为超时⽽触发重试 (commit或cancel) 就有可能导致数据不⼀致 所以要求confirm和cancel⽅法必须满⾜幂等性

TCC 中保持幂等性理解:

在⼀次事务中,try阶段执⾏⼀次, rollback或者commit执⾏⼀次。 幂等性表示 在⼀次事务中,就算try阶段执⾏多次,rollback执⾏多次或者commit⽅法执⾏多次,对当前事务是没有影响的,事务的结果和执⾏⼀次的结果是⼀致的。

2、幂等性问题解决

改造 NongUserService

    @Override
    public void reduceMoney(BusinessActionContext context, int userId, double money) {
        if (StringUtils.isEmpty(TransactionResultHolder.getResult(getClass(), context.getXid()))) {
            Double moneyById = nongUserMapper.findMoneyById(userId);
            if (moneyById < money) {
                throw new RuntimeException("余额不足");
            }
            nongUserMapper.reduceMoney(userId, money);
            //锁定资源后记录状态
            TransactionResultHolder.setResult(getClass(), context.getXid(), "xxxx");
        }
    }

10.6 TCC面临的问题 - 3、悬挂问题

1、什么是悬挂

在这里插入图片描述

最简单的理解:
执⾏事务时 由于各种原因 先⾛回滚或者提交 再⾛try阶段

2、如何解决悬挂问题

1) 新建表结构

CREATE TABLE IF NOT EXISTS `tcc_fence_log`
(
 `xid` VARCHAR(128) NOT NULL COMMENT 'global id',
 `branch_id` BIGINT NOT NULL COMMENT 'branch id',
 `action_name` VARCHAR(64) NOT NULL COMMENT 'action name',
 `status` TINYINT NOT NULL COMMENT 'status(tried:1;committ
ed:2;rollbacked:3;suspended:4)',
 `gmt_create` DATETIME(3) NOT NULL COMMENT 'create time',
 `gmt_modified` DATETIME(3) NOT NULL COMMENT 'update time',
 PRIMARY KEY (`xid`, `branch_id`),
 KEY `idx_gmt_modified` (`gmt_modified`),
 KEY `idx_status` (`status`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

2) 业务系统的业务方法,开启防悬挂
在这里插入图片描述

10.7 TCC微服务场景

1、微服务场景搭建

见 gitee : https://gitee.com/houchen1996/seata-shangma 的模块seata-tcc-cloud-order

2、TCC解决微服务的分布式事务问题

见 gitee : https://gitee.com/houchen1996/seata-shangma 的模块seata-tcc-cloud-order

3、TCC使用表结构方式同时解决上述提到的三大问题

暂时没看,实在不想敲了!

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值