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

Seata TCC 实战笔记:从零搭建分布式事务 Demo (含源码)

大家好!最近我们深入分布式事务领域,从 CAP、BASE、2PC、3PC 等理论,终于来到实战环节。这篇笔记将带你用 Seata 的 TCC(Try-Confirm-Cancel)模式,搭建一个经典的跨服务银行转账 Demo,希望对你有所启发!😉

TCC 模式概述 🤔

  • Try:检查业务可行性,预留资源(如冻结账户金额)。
  • Confirm:所有服务的 Try 都成功后,确认之前预留的操作(如实际扣款)。
  • Cancel:若任何一个 Try 失败,释放之前预留的资源(如解冻金额)。

优点:性能优于 XA,不依赖数据库强锁。

挑战:业务代码侵入性强,需要自行处理幂等、空回滚、资源悬挂等问题。


Seata 的优势 🌟

Seata 的 TCC 模式帮助我们简化:

  1. 事务协调:Seata Server (TC) 管理全局事务状态,自动驱动 Confirm/Cancel。
  2. 接口定义简化:通过 @LocalTCC 和 @TwoPhaseBusinessAction 注解定义 TCC 接口。
  3. 自动空回滚:若 Try 未成功,框架自动跳过 Cancel 调用。
  4. 上下文传递BusinessActionContext 中携带 XID、分支 ID、业务参数,方便实现幂等。

注意:幂等与悬挂仍需开发者在 Confirm/Cancel 中实现额外逻辑。


实战 Demo:银行转账 TCC 版

技术栈

  • Java 17
  • Spring Boot 3.1.12
  • Spring Data JPA (Hibernate)
  • Seata 1.7.0
  • H2 内存数据库
  • Maven

环境准备

  1. 本地安装 Docker。
  2. 克隆项目:

    git clone https://github.com/Wilsoncyf/seata-demo.git
    cd seata-demo

启动 Seata Server

docker run --name seata-server \-p 8091:8091 \-e SEATA_MODE=file \-d seataio/seata-server:1.7.0

关键代码解读

1. TCC 接口定义 (AccountTccAction.java)
@LocalTCC
public interface AccountTccAction {@TwoPhaseBusinessAction(name = "AccountTccAction",commitMethod = "confirm",rollbackMethod = "cancel")boolean prepare(BusinessActionContext actionContext,@BusinessActionContextParameter(paramName = "userId") String userId,@BusinessActionContextParameter(paramName = "amount") BigDecimal amount);boolean confirm(BusinessActionContext actionContext);boolean cancel(BusinessActionContext actionContext);
}
  • @LocalTCC:标记 TCC 接口。
  • @TwoPhaseBusinessAction:关联 Try、Confirm、Cancel 方法。
  • @BusinessActionContextParameter:指定跨阶段传递的参数。
2. TCC 接口实现 (AccountTccActionImpl.java)
@Component("accountTccAction")
public class AccountTccActionImpl implements AccountTccAction {// 注入 Repository@Override@Transactionalpublic boolean prepare(BusinessActionContext ctx, String userId, BigDecimal amount) {// 冻结金额 (更新 frozenBalance)log.info("TCC Prepare - 冻结账户 {} 金额 {} 成功", userId, amount);return true;}@Override@Transactionalpublic boolean confirm(BusinessActionContext ctx) {String txId = ctx.getXid();String branchId = String.valueOf(ctx.getBranchId());// 幂等判断if (transactionLogRepository.existsByTxIdAndBranchId(txId, branchId)) return true;// 获取参数并扣款 + 记录日志transactionLogRepository.save(new TransactionLog(...));log.info("TCC Confirm - 确认账户 {} 扣款 {} 成功", userId, amount);return true;}@Override@Transactionalpublic boolean cancel(BusinessActionContext ctx) {String txId = ctx.getXid();String branchId = String.valueOf(ctx.getBranchId());// 幂等判断if (transactionLogRepository.existsByTxIdAndBranchId(txId, branchId)) return true;// 解冻逻辑 + 记录日志transactionLogRepository.save(new TransactionLog(...));log.info("TCC Cancel - 解冻账户 {} 金额 {} 成功", userId, amount);return true;}
}
  • Try:冻结资产。
  • Confirm:实际扣款 & 幂等日志。
  • Cancel:释放冻结 & 幂等日志。
3. 事务发起方 (TransferService.java)
@Service
public class TransferService {@GlobalTransactional(timeoutMills = 60000, name = "seata-tcc-transfer-demo")public void transfer(String fromUserId, String toUserId, BigDecimal amount) {log.info("Global Transaction Start...");boolean ok = accountTccAction.prepare(null, fromUserId, amount);if (!ok) throw new RuntimeException("冻结失败");log.info("TCC Try FROM 成功");// 可继续调用收款方 Try...log.info("Global Transaction End - All Try phases successful.");}
}
  • @GlobalTransactional:开启全局事务。
  • 无需手动调用 confirm/cancel,Seata 自动处理。

测试结果

场景日志流程数据库状态
成功转账Prepare → Confirm扣款 & 冻结一致
模拟异常回滚Prepare → Cancel解冻 & 回滚到初始状态

源码地址

🔗 GitHub - Wilsoncyf/seata-demo

更多运行、调试说明见仓库中的 README.md


总结与思考

  1. TCC vs XA/Saga/AT:根据一致性、性能、开发成本权衡选型。
  2. 幂等 & 悬挂:框架不完全覆盖,需在业务实现中处理。
  3. 扩展:可结合可靠消息、Saga 模式,满足不同场景。

欢迎在评论区交流问题与建议!💬

相关文章:

  • Android 常用输入控件
  • 6.城市综合管廊工程
  • FastApi快速实践
  • 一键获取当前项目的所有文件结构并保存到文本文件
  • ​​工业机器人智能编程:从示教器到AI自主决策​​
  • 雅思听力--75个重点单词/词组
  • 在JSP写入Text文件方法指南
  • go语言实现用户管理系统
  • 【2025软考高级架构师】——2024年11月份真题与解析
  • 使用 OpenCV 和 Dlib实现轮廓绘制
  • 在写setup时遇到的问题与思考
  • 【2025软考高级架构师】——知识脑图总结
  • 管理配置信息和敏感信息
  • 【2025最新】Baichuan-M1-instruct部署教程
  • CPU缓存
  • 湖北理元理律师事务所:债务优化的合规化探索
  • 【大模型架构-Transformer、Mamba、Hyena】
  • 【day02】牛牛的快递 | 最小花费爬楼梯 | 数组中两个字符串的最小距离
  • UNet 改进(22):结合Transformer结构
  • 【RocketMQ Broker 相关源码】- broker 启动源码(1)
  • 听炮检书:柳诒徵1927年的选择
  • 干细胞从科研到市场应用有多远?发展还面临何挑战?
  • 巴菲特掌舵伯克希尔60年后将卸任CEO,库克:认识他是人生中最珍贵的经历之一
  • 2类药物别乱吃,严重可致肝肾衰竭!多人已中招
  • “名额5分钟抢完”,一场花费上万元:越野赛凭什么这么火?
  • 国际观察|韩国在政局多重不确定性中迎接总统选举