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

Seata TCC 生产级(空回滚+悬挂+幂等)+ AT/TCC 混合使用

AT 模式基于 undo_log 实现自动回滚,无代码侵入,适合常规业务;
TCC 模式通过业务层 Try-Confirm-Cancel 手动实现分布式事务,性能更高、粒度更细,适合库存、秒杀等核心交易场景。

TCC三大问题
空回滚:Try 没执行,Cancel 先执行
悬挂:Cancel 执行完,Try 才来
幂等:Confirm/Cancel 重复调用

一、项目标准结构(清晰可维护)

your-project/ ├── src/main/java/com/example/ │ ├── config/ # Seata 配置 │ ├── entity/ # 实体类 │ ├── mapper/ # DAO 层 │ ├── service/ # 业务层 │ │ ├── tcc/ # TCC 专用包 │ │ │ ├── StockTccService.java # TCC 接口 │ │ │ └── StockTccServiceImpl.java # TCC 实现(含三大问题解决) │ │ ├── OrderService.java # 分布式事务发起方(AT+TCC混合) │ │ └── AccountService.java # AT 模式服务 │ └── controller/ # 接口入口 └── resources/ └── mapper/ # MyBatis XML

二、必须执行的 SQL(2张表)

1. TCC 事务状态表(解决:空回滚、悬挂、幂等

CREATETABLE`tcc_transaction`(`xid`varchar(100)NOTNULL,`branch_id`bigintNOTNULL,`status`tinyintNOTNULLCOMMENT'0=Try中 1=Confirm完成 2=Cancel已回滚',`create_time`datetimeDEFAULTCURRENT_TIMESTAMP,`update_time`datetimeDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,PRIMARYKEY(`xid`,`branch_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

2. 库存表(冻结字段实现 TCC 资源预留

CREATETABLE`stock`(`id`bigintNOTNULLAUTO_INCREMENT,`goods_id`bigintNOTNULL,`stock`intNOTNULLDEFAULT0,`frozen`intNOTNULLDEFAULT0COMMENT'冻结库存',PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;

三、POM 依赖

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>

四、核心 TCC 代码

4.1 TCC 接口(固定写法)

packagecom.example.service.tcc;importio.seata.rm.tcc.api.*;@LocalTCCpublicinterfaceStockTccService{@TwoPhaseBusinessAction(name="deductStockTcc",commitMethod="confirm",rollbackMethod="cancel")booleantryDeductStock(BusinessActionContextcontext,@BusinessActionContextParameter("goodsId")LonggoodsId,@BusinessActionContextParameter("num")Integernum);booleanconfirm(BusinessActionContextcontext);booleancancel(BusinessActionContextcontext);}

4.2 TCC 实现类(空回滚 + 悬挂 + 幂等

packagecom.example.service.tcc;importio.seata.rm.tcc.api.BusinessActionContext;importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Service;importcom.example.mapper.StockMapper;importcom.example.mapper.TccTransactionMapper;importcom.example.entity.TccTransaction;importjavax.annotation.Resource;@Slf4j@ServicepublicclassStockTccServiceImplimplementsStockTccService{@ResourceprivateStockMapperstockMapper;@ResourceprivateTccTransactionMappertccMapper;// ==================== Try:检查 + 冻结 ====================@OverridepublicbooleantryDeductStock(BusinessActionContextcontext,LonggoodsId,Integernum){Stringxid=context.getXid();longbranchId=context.getBranchId();// 1. 幂等校验:已执行则直接返回TccTransactiont=tccMapper.get(xid,branchId);if(t!=null){returntrue;}// 2. 防悬挂:Cancel 已执行,拒绝 Tryif(t!=null&&t.getStatus()==2){thrownewRuntimeException("交易已回滚,禁止操作");}// 3. 记录事务状态tccMapper.add(xid,branchId,0);// 4. 业务校验 + 冻结库存Integeravailable=stockMapper.getAvailable(goodsId);if(available==null||available<num){thrownewRuntimeException("库存不足");}stockMapper.freeze(goodsId,num);log.info("✅ TCC Try 完成:goodsId={},冻结={}",goodsId,num);returntrue;}// ==================== Confirm:确认扣减 ====================@Overridepublicbooleanconfirm(BusinessActionContextcontext){Stringxid=context.getXid();longbranchId=context.getBranchId();LonggoodsId=(Long)context.getActionContext("goodsId");Integernum=(Integer)context.getActionContext("num");// 幂等TccTransactiont=tccMapper.get(xid,branchId);if(t==null||t.getStatus()==1)returntrue;// 扣减stockMapper.deduct(goodsId,num);tccMapper.update(xid,branchId,1);log.info("✅ TCC Confirm 完成:最终扣减");returntrue;}// ==================== Cancel:回滚解冻 ====================@Overridepublicbooleancancel(BusinessActionContextcontext){Stringxid=context.getXid();longbranchId=context.getBranchId();LonggoodsId=(Long)context.getActionContext("goodsId");Integernum=(Integer)context.getActionContext("num");// 1. 幂等TccTransactiont=tccMapper.get(xid,branchId);if(t!=null&&t.getStatus()==2)returntrue;// 2. 空回滚:Try 未执行,直接标记为已回滚if(t==null){tccMapper.add(xid,branchId,2);returntrue;}// 3. 解冻if(t.getStatus()==0){stockMapper.unfreeze(goodsId,num);}tccMapper.update(xid,branchId,2);log.info("✅ TCC Cancel 完成:解冻回滚");returntrue;}}

五、Mapper 接口(完整)

5.1 TccTransactionMapper

packagecom.example.mapper;importcom.example.entity.TccTransaction;importorg.apache.ibatis.annotations.Param;importorg.springframework.stereotype.Repository;@RepositorypublicinterfaceTccTransactionMapper{TccTransactionget(@Param("xid")Stringxid,@Param("branchId")LongbranchId);intadd(@Param("xid")Stringxid,@Param("branchId")LongbranchId,@Param("status")Integerstatus);intupdate(@Param("xid")Stringxid,@Param("branchId")LongbranchId,@Param("status")Integerstatus);}

5.2 StockMapper

packagecom.example.mapper;importorg.apache.ibatis.annotations.Param;importorg.springframework.stereotype.Repository;@RepositorypublicinterfaceStockMapper{IntegergetAvailable(@Param("goodsId")LonggoodsId);intfreeze(@Param("goodsId")LonggoodsId,@Param("num")Integernum);intdeduct(@Param("goodsId")LonggoodsId,@Param("num")Integernum);intunfreeze(@Param("goodsId")LonggoodsId,@Param("num")Integernum);}

六、XML SQL

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.mapper"><!-- TCC 事务 --><selectid="get"resultType="com.example.entity.TccTransaction">select * from tcc_transaction where xid=#{xid} and branch_id=#{branchId}</select><insertid="add">insert into tcc_transaction(xid,branch_id,status) values(#{xid},#{branchId},#{status})</insert><updateid="update">update tcc_transaction set status=#{status} where xid=#{xid} and branch_id=#{branchId}</update><!-- 库存 --><selectid="getAvailable"resultType="integer">select stock - frozen from stock where goods_id=#{goodsId}</select><updateid="freeze">update stock set frozen = frozen + #{num} where goods_id=#{goodsId}</update><updateid="deduct">update stock set stock=stock-#{num}, frozen=frozen-#{num} where goods_id=#{goodsId}</update><updateid="unfreeze">update stock set frozen = frozen - #{num} where goods_id=#{goodsId}</update></mapper>

七、分布式事务发起方(AT + TCC 混合使用

packagecom.example.service;importcom.example.service.tcc.StockTccService;importio.seata.spring.annotation.GlobalTransactional;importorg.springframework.stereotype.Service;importcom.example.mapper.OrderMapper;importjavax.annotation.Resource;@ServicepublicclassOrderService{@ResourceprivateOrderMapperorderMapper;@ResourceprivateAccountServiceaccountService;@ResourceprivateStockTccServicestockTccService;/** * 全流程分布式事务: * 订单(AT) + 账户(AT) + 库存(TCC) */@GlobalTransactional(rollbackFor=Exception.class)publicvoidcreateOrder(Orderorder){// 1. 创建订单(AT)orderMapper.insert(order);// 2. 扣减余额(AT)accountService.deduct(order.getUserId(),order.getPrice());// 3. 扣减库存(TCC)stockTccService.tryDeductStock(null,order.getGoodsId(),order.getNum());// 模拟异常 → 全部回滚// int i = 1 / 0;}}

八、Seata 配置(application.yml)

seata:enabled:truetx-service-group:my_groupservice:vgroup-mapping:my_group:defaultgrouplist:default:127.0.0.1:8091

九、这套代码解决了哪些生产问题?

1.空回滚问题

  • 现象:Try 没执行,Cancel 先执行
  • 解决:Cancel 中判断无事务记录 → 直接标记回滚,不做业务操作

2.悬挂问题

  • 现象:Cancel 执行完,Try 才执行 → 资源永久锁住
  • 解决:Try 执行前判断事务状态 → 已回滚则直接拒绝

3.幂等问题

  • 现象:Confirm/Cancel 被重复调用 → 重复扣减/重复解冻
  • 解决:执行前判断状态 → 已执行则直接返回

4.超卖问题

  • 解决:Try 冻结 + Confirm 最终扣减

5.分布式事务一致性

  • 订单、账户、库存任意失败 →全部自动回滚

6.AT + TCC 混合使用

  • 简单业务用 AT(零编码)
  • 核心业务用 TCC(高性能、可控)
http://www.jsqmd.com/news/532267/

相关文章:

  • 【国家级密码应用试点项目实测报告】:Python SM9性能压测数据首次公开——TPS仅87?优化后飙升至1243!
  • 2026年知名的煤炭化验设备/煤炭化验设备智能厂家选购参考汇总 - 行业平台推荐
  • 选对课比努力更重要:在线AI证书课程的选择标准与对比评测
  • 专业的生态袋、土工布、排水板生产厂家推荐★★★★★ - 企业推荐官【官方】
  • Stable Yogi Leather-Dress-Collection生产环境:日均百图稳定生成的本地化运维方案
  • 西地那非选品与使用:合规为先,精准适配 - 企业推荐官【官方】
  • 2025-2026年品牌咨询公司推荐:营收千万至十亿级企业口碑咨询机构深度解读 - 十大品牌推荐
  • HunyuanVideo-Foley音效生成:支持中文prompt理解‘地铁报站声’等场景
  • 5个Windows 10效能提升实战指南:让系统重获新生
  • 他达拉非品牌梳理 临床应用中的品质与选择要点 - 企业推荐官【官方】
  • 2026年靠谱的不锈钢商超设备/嘉兴仓储式商超设/连锁商超设备热门品牌厂家推荐 - 行业平台推荐
  • 2026年比较好的河北老式烧鸡/老式烧鸡/河北开袋即食烧鸡长期合作厂家推荐 - 行业平台推荐
  • 2026年质量好的铁皮周转箱/堆叠周转箱/工厂周转箱优质厂商精选推荐(口碑) - 行业平台推荐
  • 【OneMore插件】160+功能让OneNote效率提升3倍:从痛点到解决方案的全面升级
  • 性价比高的福州护栏、护栏网、围挡厂家推荐 - 企业推荐官【官方】
  • SDMatte持续集成与交付:利用Jenkins自动化部署模型更新
  • 2026年评价高的兰花舒棉绒/北极绒舒棉绒行业内知名厂家推荐 - 行业平台推荐
  • 2026年知名的压电陶瓷片/爆震传感器用压电陶瓷厂家推荐与选购指南 - 行业平台推荐
  • 小程序毕业设计springboot基于小程序的高校宿舍管理系统小程序
  • 从波特图到示波器:手把手教你设计运放补偿电路(以OPA2188为例)
  • 2026年质量好的维利封口贴纸不干胶标签/维利礼品标签/维利日化标签/维利茶叶标签热门厂家推荐汇总 - 行业平台推荐
  • 2026年口碑好的通过式抛丸机/型材抛丸机/履带式抛丸机/网带通过式抛丸机厂家选购参考汇总 - 行业平台推荐
  • 父级 ‘org.springframework.boot:spring-boot-starter-parent:4.0.4‘ 有问题
  • Hunyuan-MT-7B应用场景:从维汉公文到藏语病历的实战翻译
  • PyCharm社区版免费安装指南:从下载到环境配置全流程
  • ComfyUI新手教程:3步快速部署,小白也能玩转AI绘画
  • 2026年评价高的大连考公辽宁省考/大连考公笔试班实操推荐公司 - 行业平台推荐
  • High-Pass Matters: Theoretical Insights and Sheaflet-Based Design forHypergraph Neural Networks
  • 2026年靠谱的T1级后备保护器/T2级后备保护器厂家综合实力参考(2025) - 行业平台推荐
  • Qwen3-ASR-0.6B与数据可视化:语音分析仪表盘开发