Spring Cloud 系列:Seata 中TCC模式具体实现

这篇具有很好参考价值的文章主要介绍了Spring Cloud 系列:Seata 中TCC模式具体实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

https://seata.io/zh-cn/docs/dev/mode/tcc-mode

https://seata.io/zh-cn/docs/user/mode/tcc

TCC模式与AT模式非常相似,每阶段都是独立事务,不同的是TCC通过人工编码来实现数据恢复。需要实现三个方法:

  • Try:资源的检测和预留;
  • Confirm:完成资源操作业务;要求 Try 成功 Confirm 一定要能成功。
  • Cancel:预留资源释放,可以理解为try的反向操作。

Seata的TCC模型

Seata中的TCC模型依然延续之前的事务架构,如图:

Spring Cloud 系列:Seata 中TCC模式具体实现,spring cloud,oracle,数据库

优缺点

TCC模式的每个阶段是做什么的?

  • Try:资源检查和预留
  • Confirm:业务执行和提交
  • Cancel:预留资源的释放

TCC的优点是什么?

  • 一阶段完成直接提交事务,释放数据库资源,性能好
  • 相比AT模型,无需生成快照,无需使用全局锁,性能最强
  • 不依赖数据库事务,而是依赖补偿操作,可以用于非事务型数据库

TCC的缺点是什么?

  • 有代码侵入,需要人为编写try、Confirm和Cancel接口,太麻烦
  • 软状态,事务是最终一致
  • 需要考虑Confirm和Cancel的失败情况,做好幂等处理

事务悬挂和空回滚

1)空回滚

当某分支事务的try阶段阻塞时,可能导致全局事务超时而触发二阶段的cancel操作。在未执行try操作时先执行了cancel操作,这时cancel不能做回滚,就是空回滚

如图:

Spring Cloud 系列:Seata 中TCC模式具体实现,spring cloud,oracle,数据库

执行cancel操作时,应当判断try是否已经执行,如果尚未执行,则应该空回滚。

2)业务悬挂

对于已经空回滚的业务,之前被阻塞的try操作恢复,继续执行try,就永远不可能confirm或cancel ,事务一直处于中间状态,这就是业务悬挂

执行try操作时,应当判断cancel是否已经执行过了,如果已经执行,应当阻止空回滚后的try操作,避免悬挂

实现TCC模式

决空回滚和业务悬挂问题,必须要记录当前事务状态,是在try、还是cancel?

1)思路分析

这里我们定义一张表:

CREATE TABLE `account_freeze_tbl` (
  `xid` varchar(128) NOT NULL,
  `user_id` varchar(255) DEFAULT NULL COMMENT '用户id',
  `freeze_money` int(11) unsigned DEFAULT '0' COMMENT '冻结金额',
  `state` int(1) DEFAULT NULL COMMENT '事务状态,0:try,1:confirm,2:cancel',
  PRIMARY KEY (`xid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

其中:

  • xid:是全局事务id
  • freeze_money:用来记录用户冻结金额
  • state:用来记录事务状态

那此时,我们的业务开怎么做呢?

  • Try业务:
    • 记录冻结金额和事务状态到account_freeze表
    • 扣减account表可用金额
  • Confirm业务
    • 根据xid删除account_freeze表的冻结记录
  • Cancel业务
    • 修改account_freeze表,冻结金额为0,state为2
    • 修改account表,恢复可用金额
  • 如何判断是否空回滚?
    • cancel业务中,根据xid查询account_freeze,如果为null则说明try还没做,需要空回滚
  • 如何避免业务悬挂?
    • try业务中,根据xid查询account_freeze ,如果已经存在则证明Cancel已经执行,拒绝执行try业务

接下来,我们改造account-service,利用TCC实现余额扣减功能。

2)声明TCC接口

TCC的Try、Confirm、Cancel方法都需要在接口中基于注解来声明,

我们在account-service项目中的com.mcode.account.service包中新建一个接口,声明TCC三个接口:

package com.mcode.account.service;

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 {

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
                @BusinessActionContextParameter(paramName = "money")int money);

    boolean confirm(BusinessActionContext ctx);

    boolean cancel(BusinessActionContext ctx);
}
3)编写实现类

在account-service服务中的com.mcode.account.service.impl包下新建一个类,实现TCC业务:

package com.mcode.account.service.impl;

import com.mcode.account.entity.AccountFreeze;
import com.mcode.account.mapper.AccountFreezeMapper;
import com.mcode.account.mapper.AccountMapper;
import com.mcode.account.service.AccountTCCService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
public class AccountTCCServiceImpl implements AccountTCCService {

    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private AccountFreezeMapper freezeMapper;

    @Override
    @Transactional
    public void deduct(String userId, int money) {
        // 0.获取事务id
        String xid = RootContext.getXID();
        // 1.扣减可用余额
        accountMapper.deduct(userId, money);
        // 2.记录冻结金额,事务状态
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freeze.setXid(xid);
        freezeMapper.insert(freeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        // 1.获取事务id
        String xid = ctx.getXid();
        // 2.根据id删除冻结记录
        int count = freezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        // 0.查询冻结记录
        String xid = ctx.getXid();
        AccountFreeze freeze = freezeMapper.selectById(xid);

        // 1.恢复可用余额
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        // 2.将冻结金额清零,状态改为CANCEL
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }
}

四种模式对比

我们从以下几个方面来对比四种实现:

  • 一致性:能否保证事务的一致性?强一致还是最终一致?
  • 隔离性:事务之间的隔离性如何?
  • 代码侵入:是否需要对业务代码改造?
  • 性能:有无性能损耗?
  • 场景:常见的业务场景

如图:

Spring Cloud 系列:Seata 中TCC模式具体实现,spring cloud,oracle,数据库文章来源地址https://www.toymoban.com/news/detail-818379.html

到了这里,关于Spring Cloud 系列:Seata 中TCC模式具体实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java微服务分布式事务框架seata的TCC模式

    🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 专栏 描述 Java项目实战 介绍Java组件安装、使用;手写框架等 Aws服务器实战 Aws Linux服务器上操作nginx、git、JDK、Vue Jav

    2024年03月23日
    浏览(45)
  • Spring Cloud Alibaba 整合Seata 之概念介绍及Seata-server搭建

    目录 前言 基础介绍 官方文档 模式分类 角色介绍 Seata Server 部署 -  docker-compose  数据库 服务器  nacos配置 docker-compose.yaml 启动 后记 Seata 是 阿里巴巴 开源的 分布式事务中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题。 主要指讲述

    2024年02月07日
    浏览(82)
  • 《微服务实战》 第三十章 分布式事务框架seata TCC模式

    第三十章 分布式事务框架seata TCC模式 第二十九章 分布式事务框架seata AT模式 本章节介绍分布式事务框架seata TCC模式,上一章节介绍seata以及集成到Springboot、微服务框架里。 一个分布式的全局事务,整体是 两阶段提交 的模型。全局事务是由若干分支事务组成的,分支事务要

    2024年02月12日
    浏览(46)
  • Spring Cloud Alibaba全家桶(九)——分布式事务组件Seata

    本文小新为大家带来 分布式事务组件Seata 相关知识,具体内容包括 分布式事务简介 (包括: 事务简介 , 本地事务 , 分布式事务典型场景 , 分布式事务理论基础 , 分布式事务解决方案 ), 分布式事务Seata使用 (包括: Seata是什么 , Seata的三大角色 , Seata的设计思路

    2024年02月03日
    浏览(62)
  • 【Spring Cloud系列】 雪花算法原理及实现

    分布式高并发的环境下,常见的就是12306节日订票,在大量用户同是抢购一个方向的票,毫秒级的时间下可能生成数万个订单,此时为确保生成订单ID的唯一性变得至关重要。此时秒杀环境下,不仅要保障ID唯一性,还得确保ID生成的优先度。 全局唯一 :不能出现重复的ID号,

    2024年02月09日
    浏览(37)
  • 【Spring Cloud Alibaba Seata 处理分布式事务】——每天一点小知识

                                                                                   💧 S p r i n g C l o u d A l i b a b a S e a t a 处理分布式事务 color{#FF1493}{Spring Cloud Alibaba Seata 处理分布式事务} Sp r in g Cl o u d A l ibaba S e a t a 处理分布式事务 💧

    2024年02月12日
    浏览(41)
  • Spring Cloud的断路器模式是什么?如何使用断路器?Spring Cloud的配置管理是怎样实现的?

    Spring Cloud的断路器模式是一种应对微服务架构中潜在故障的解决方案。在微服务架构中,不同的服务相互依赖,当某个服务出现故障或响应缓慢时,可能会导致级联故障,影响整个系统的可用性。 断路器模式通过在服务调用链路上插入断路器,在服务出现故障时,可以快速失

    2024年02月15日
    浏览(42)
  • 【合集】Spring Cloud 组件——架构进化史话 & Eureka,Nacos,OpenFeign,Ribbon,Sentinel,Gateway ,Seata+事务. . .

    Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,领导选举,分布式会话,集群状态)。 注意: 首先,尽管Spring Cloud带有“Cloud”这个单词,但它并不是云计算解

    2024年02月08日
    浏览(40)
  • Spring Authorization Server 1.1 扩展实现 OAuth2 密码模式与 Spring Cloud 的整合实战

    项目源码 :youlai-mall 通过 Spring Cloud Gateway 访问认证中心进行认证并获取得到访问令牌。 再根据访问令牌 access_token 获取当前登录的用户信息。 Spring Security OAuth2 的最终版本是2.5.2,并于2022年6月5日正式宣布停止维护。Spring 官方为此推出了新的替代产品,即 Spring Authorization

    2024年02月04日
    浏览(46)
  • 【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合!

    🎉🎉 欢迎光临,终于等到你啦 🎉🎉 🏅我是 苏泽 ,一位对技术充满热情的探索者和分享者。🚀🚀 🌟持续更新的专栏 《Spring 狂野之旅:从入门到入魔》 🚀 本专栏带你从Spring入门到入魔   这是苏泽的个人主页可以看到我其他的内容哦👇👇 努力的苏泽 http://suzee.blog.

    2024年03月10日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包