tcc模式核心是将业务逻辑拆分为try-confirm-cancel三阶段:try阶段仅校验与冻结资源,confirm阶段幂等提交(冻结转生效),cancel阶段幂等释放(含空回滚防护),由事务协调器驱动,不依赖数据库xa。

Java 中用 TCC 模式重构微服务分布式事务,核心不是加框架,而是把原本“一步做完”的业务逻辑,按资源检查、预留、确认/回滚三个阶段重新设计,并让每个服务暴露 try、confirm、cancel 三个可独立调用的接口。
拆解原有业务为三阶段操作
比如订单支付原流程是:更新订单状态 → 扣库存 → 增积分。现在要为每个服务单独定义三个方法:
- Try 阶段:只做校验和资源冻结,不改主数据。例如订单服务检查状态是否可支付、生成预订单号但不落终态;库存服务查库存够不够,把要扣的数量记入“冻结库存”字段;积分服务预生成积分流水号,状态设为“待生效”。
- Confirm 阶段:真正提交,把冻结转为生效。订单状态置为“已支付”,库存从“可用”减、“冻结”清零,积分流水状态改为“已发放”。这个操作必须幂等——重复调用不能多发积分或多扣库存。
- Cancel 阶段:释放冻结资源。订单回退到“待支付”,库存冻结量归零(不碰可用量),积分流水标记为“已取消”。同样要求幂等,且要能处理“没 try 过就 cancel”的空回滚场景。
引入事务协调器统一调度
TCC 不依赖数据库 XA,靠外部协调器驱动两阶段执行。常用方案有:
- 自研轻量协调器:用 Redis 或 DB 记录事务 ID、参与者列表、当前状态(TRYING / CONFIRMING / CANCELLING),通过定时任务+失败重试保障最终一致性;
- 集成 Seata TCC 模式:在 service 方法上加
@TwoPhaseBusinessAction注解,声明 try 方法名及 confirm/cancel 对应方法,Seata 会自动记录分支事务、发起二阶段调用; - 避免强依赖中心节点:协调逻辑可下沉到发起方(TM),由它按序调用各服务的 try 接口,成功后广播 confirm,失败则反向调用 cancel(注意 cancel 顺序与 try 相反)。
关键细节必须处理到位
光写三个接口远远不够,以下四点漏掉任一都可能引发数据错乱:
- 幂等性:每个接口开头用唯一事务 ID + 操作类型(try/confirm/cancel)做去重,比如插入唯一索引记录或查表判断是否已执行;
- 空回滚防护:cancel 被调用时,先查对应事务的 try 是否已执行,若未执行(即无 try 记录),仍允许 cancel 成功,但需记录日志并跳过实际释放动作;
- 悬挂控制:如果 cancel 已执行,后续又收到同事务 ID 的 try 请求,直接拒绝并返回失败,防止冻结资源被二次占用;
- 业务可见性:用户查询订单时,看到的是“支付中”状态;查库存时,“可销售数 = 原值 − 冻结数”,避免误导其他并发下单请求。
改造后效果与取舍
TCC 把锁从数据库层提到业务层,换来更高并发和自主可控的资源隔离策略,代价是代码侵入性强、开发成本高。适合资金类、库存类等对一致性敏感、且业务规则清晰可拆分的场景。不适合字段频繁变更、状态流转复杂、或无法明确划分“预留”与“确认”边界的业务。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











