微服务架构下,一个业务操作跨多个服务、多个数据库,本地事务管不住全局一致性,这就是分布式事务要解决的问题。分布式事务的方案很多,本文对比最常用的Seata AT模式与TCC模式,给出选型建议和代码示例,供后端开发做技术选型时参考。
分布式事务的三种基础模型
业界主流的分布式事务方案可归为三类:
2PC(两阶段提交):XA协议为代表,强一致,但锁资源时间长、性能差。
TCC(Try-Confirm-Cancel):业务层补偿,无锁,需要三个接口,开发量大。
本地消息表/事务消息:最终一致性,吞吐高,适合不要求实时一致的场景。
另外还有Saga长事务,适合多步骤编排。选型核心看两点:业务对一致性的要求,以及是否允许中间状态被外部看到。
Seata AT模式:自动补偿的无侵入方案
AT模式基于2PC的变体,由框架自动生成补偿SQL,业务代码几乎无侵入。核心流程:
1. 事务管理器(TC)开启全局事务。
2. 分支事务注册到TC,执行本地SQL。
3. 提交前,TC协调各分支做二阶段提交;失败则反向执行补偿SQL回滚。
AT模式依赖全局锁和undo_log表,本地库自动维护undo_log回滚数据。Java接入示例:
@GlobalTransactional(name = "create-order", timeoutMills = 30000)
public void createOrder(OrderDTO dto) {
orderService.insert(dto); // 本地事务,自动注册分支
inventoryService.deduct(dto); // 跨服务调用
accountService.deduct(dto.getAmount());
}
只要在入口方法加@GlobalTransactional注解,分支服务接入seata客户端,框架自动完成回滚。数据一致性靠undolog,性能损耗主要在一阶段锁等待和二阶段回滚。
AT模式适用边界与注意事项
AT模式适合读多写少、对性能不太敏感、表结构规整的业务。三个容易踩的坑:
1. 全局锁范围大:高并发下热点行冲突明显,压测时要观察全局锁等待时间。
2. undo_log清理:Seata会定期清理,但要确认表结构兼容。
3. 不支持跨数据库DDL和部分SQL语法:像DDL语句无法生成逆向SQL。
如果业务对吞吐要求极高,或跨服务链路很长,AT模式的锁开销会放大,此时考虑TCC。
TCC模式:业务补偿的强一致方案
TCC把一次事务拆成Try(预留资源)、Confirm(确认提交)、Cancel(取消补偿)三个阶段,全程由业务代码控制,性能远好于2PC,且无全局锁。
public class InventoryServiceTcc {
@LocalTCC
@TwoPhaseBusinessAction(name = "deductInventory",
commitMethod = "confirmDeduct", rollbackMethod = "cancelDeduct")
public boolean tryDeduct(BusinessActionContext ctx, Long goodsId, int num) {
// 1. 检查库存
// 2. 冻结库存(冻结字段 + 减可用)
return inventoryMapper.freeze(goodsId, num) > 0;
}
public boolean confirmDeduct(BusinessActionContext ctx) {
// 扣减冻结库存,写入正式库存表
return inventoryMapper.confirm(ctx.getActionContext("goodsId")) > 0;
}
public boolean cancelDeduct(BusinessActionContext ctx) {
// 释放冻结库存
return inventoryMapper.unfreeze(ctx.getActionContext("goodsId")) > 0;
}
}
TCC的关键是三个方法都要幂等(重试不会产生重复扣减),且Try阶段要防止数据被并发污染。业务复杂度随接口数量线性增长,事务链路每多一个服务,就要多写一套TCC,维护成本高。
Seata TCC与AT的选型对比
AT:开发量小,框架自动回滚,但全局锁对热点冲突明显,适合中小流量。
TCC:无全局锁、性能可控,但每个分支要写三个方法并保证幂等,适合高并发核心链路(支付、库存)。
没有万能方案,同一系统里不同服务可以混用:核心账户用TCC,普通订单用AT,报表类对账直接用消息队列最终一致性。
分布式事务之外的替代思路
不少场景不需要分布式事务:
1. 本地消息表:业务和消息写入同一库,消费方再拉取,最终一致。
2. RocketMQ事务消息:半消息+本地事务回调,可靠投递。
3. 事件驱动+幂等消费:把跨服务操作改成发事件,消费方幂等处理,系统解耦更彻底。
设计上能拆分就拆分,把事务边界控制在单个服务内,是成本最低的”分布式事务”。不得不跨服务时,再按一致性强度、吞吐、开发成本三要素选型,并把幂等设计在全局做扎实。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/fen-bu-shi-shi-wu-shi-zhan-seataat-mo-shi-yu-tcc-fang-an/