摘要:Seata 不仅仅是 AT 模式。作为阿里开源的分布式事务旗舰,Seata 提供了 AT、TCC、Saga 和 XA 四种模式,涵盖了从"强一致"到"最终一致"的全方位需求。本文将拒绝理论空谈,从架构师视角深度剖析这四种模式的适用边界,并重点对比 AT、TCC 与 Saga 的实战权衡。
引言:不要拿着锤子找钉子
在 Spring Cloud Alibaba 生态中,很多开发者对 Seata 的认知停留在:"加个 @GlobalTransactional 注解,一切自动搞定。"
这是 Seata 的 AT 模式(Automatic Transaction) ,也是它最吸引人的"杀手锏"。但在高并发、长链路或涉及非关系型数据库(Redis/MongoDB)的复杂场景下,AT 模式的全局锁机制往往会成为系统的吞吐量瓶颈。
Seata 的真相是:它是一个支持四种模式的分布式事务平台。
-
AT 模式:省心的自动挡(适合大多数 CRUD)。
-
TCC 模式:精细的手动挡(适合核心资金链路)。
-
Saga 模式:长跑型选手(适合长业务流程)。
-
XA(2PC) 模式:标准的老古董(适合对强一致性有执念的传统场景)。
本文将重点拆解 AT、TCC、Saga 这三位互联网架构中的"常客",帮你理清选型的底层逻辑。

核心战场:AT vs TCC vs Saga 深度对比
我们抛开 XA(因为它依赖数据库层面的 2PC,性能在互联网场景通常不可接受),聚焦于三种应用层模式的较量。
1. 架构级横向测评表
这三种模式在一致性、隔离性、性能 和改造成本上呈现出明显的"不可能三角":
| 维度 | AT 模式 (默认/自动) | TCC 模式 (Try-Confirm-Cancel) | Saga 模式 (长事务补偿) |
|---|---|---|---|
| 核心机制 | 二阶段提交 + 全局锁。 框架自动生成回滚日志 (Undo Log)。 | 资源预留 (2PC)。 手动实现 Try(冻结)、Confirm(提交)、Cancel(解冻)。 | 一往无前 + 失败补偿。 直接提交本地事务,失败则反向执行补偿操作。 |
| 性能/吞吐 | 中/低 全局锁(Global Lock)导致并发写冲突时需等待,长事务会阻塞数据库连接。 | 高 无全局锁,但 Try 阶段需锁定部分资源(如冻结金额),性能损耗主要在业务逻辑。 | 极高 本地事务提交即释放 DB 锁,无全局锁等待,链路越长优势越明显。 |
| 隔离性 | 好 (写隔离) Seata 帮你处理了写隔离,但在默认隔离级别下可能读到中间状态。 | 极好 通过 Try 阶段的"资源冻结",在业务层面实现了完美的隔离性。 | 差 (读隔离缺失) 因为没有锁,A 阶段提交后,B 阶段未开始前,用户能看到"中间状态"。 |
| 代码侵入 | 极低 (低代码) 仅需注解,业务代码 0 感知。 | 极高 (高代码) 一个接口需要拆分成 3 个方法,开发量 X3。 | 高 (高代码) 需要编写正向业务逻辑和反向补偿逻辑。 |
| 典型场景 | 常规 B 端业务、内部管理系统、短链路 CRUD。 | 支付、交易、账务。 (必须保证钱是对的,不能有脏读)。 | 跨境物流、出行订票、复杂审批。 (链路长、跨老旧系统、跨非 ACID 存储)。 |
2. 模式深度解析
AT 模式:披着"强一致"外衣的自动挡
-
原理:Seata 代理了你的 JDBC DataSource。当你执行 SQL 时,Seata 偷偷记录了"更新前"和"更新后"的数据快照。如果事务失败,它利用快照把数据还原。
-
死穴 :全局锁。如果你的业务耗时 5 秒,这 5 秒内这行数据谁都不能改。如果全公司都在操作同一张热点表(如库存表),系统会瞬间瘫痪。
TCC 模式:追求极致掌控的特种兵
-
原理:不依赖数据库事务,完全靠业务逻辑控制。
-
Try :比如转账,先检查余额,然后冻结 100 元(余额表不动,增加冻结字段)。
-
Confirm:真正的扣减余额,清除冻结。
-
Cancel:解冻资金。
-
-
王牌 :隔离性 。因为 Try 阶段冻结了资源,其他并发事务是看不到这部分资源的,所以不会有"超卖"或"脏读"问题。适合对资金极其敏感的场景。
Saga 模式:化整为零的长跑冠军
-
原理:把一个长事务拆成 T1, T2, T3... 每个 Tx 执行完立刻提交给数据库,不占锁。如果 T3 失败了,依次执行 C2, C1 进行补偿。
-
王牌 :高吞吐 & 兼容性。它不关心你的数据库是不是 MySQL,甚至可以是一个 Redis 操作或发一封邮件。只要你能写出"取消操作/退款操作",Saga 就能编排。
进阶实战:Seata Saga 的状态机魔法
Saga 模式的难点在于"流程编排"。Seata 提供了一个基于 状态机 (State Machine) 的引擎,允许你用 JSON 定义流程,而不是写一堆 if-else。
1. 场景模拟:全链路电商下单
流程:库存扣减 -> 风控校验(外部API) -> 物流下单(慢) -> 余额扣减
-
AT 模式问题:外部 API 和物流都很慢,导致数据库连接被长时间占用,连接池耗尽。
-
Saga 模式解法:库存扣完就释放锁。风控慢慢测,物流慢慢下。失败了再发个指令把库存加回去。
2. Seata Saga JSON 定义 (简化版)
{
"Name": "ECommerceOrderSaga",
"States": {
"DeductInventory": {
"Type": "ServiceTask",
"ServiceName": "inventoryService",
"ServiceMethod": "deduct",
"CompensateState": "CompensateInventory", // 定义回滚路径
"Next": "RiskCheck"
},
"RiskCheck": {
"Type": "ServiceTask",
"ServiceName": "riskService",
"ServiceMethod": "check",
"CompensateState": "CompensateRisk", // 即使是外部API,也可以定义撤销逻辑
"Next": "CreateLogistics"
}
// ... 后续流程
}
}
架构师必修:分布式事务的三大恶魔
无论你选择 TCC 还是 Saga,只要涉及"补偿/取消",就必须在代码层面处理好这三个棘手问题,否则会引发严重的数据事故:
-
空回滚 (Null Rollback)
-
现象:Seata 调用 Try/正向操作时超时了,直接触发 Cancel/补偿。其实 Try 根本没执行,Cancel 却执行了(例如:没扣款,却退款了)。
-
对策 :补偿方法必须判空。检查正向操作是否留下了痕迹(如流水号),无痕迹则直接 Return。
-
-
悬挂 (Hanging)
-
现象:网络拥堵,Cancel 比 Try 先到达。Cancel 执行完后,迟到的 Try 来了,导致正向业务执行了且无法被回滚。
-
对策:记录全局事务状态。Try 执行前检查是否已经有 Rollback 记录,若有则拒绝执行。
-
-
幂等 (Idempotency)
-
现象:网络抖动导致 Confirm/Cancel 被重复调用。
-
对策:所有接口必须支持幂等(防重表、Token 机制)。
-
终极决策树:Seata 模式选型指南
在做架构评审时,请根据以下逻辑对号入座:
-
是核心资金/交易链路吗?
-
是 (不能容忍任何脏读/中间状态):首选 TCC。虽然累点,但为了钱的安全,值得。
-
否:往下看。
-
-
数据源支持 ACID 事务吗?
-
否 (Redis, MongoDB, 外部 API):只能选 Saga(或 TCC)。AT 和 XA 没法用。
-
是(MySQL 等):往下看。
-
-
业务链路是否"长"或"慢"?
-
是 (跨多个服务,耗时 > 500ms):推荐 Saga。避免 AT 模式的长事务锁死数据库。
-
否 (简单短平快):首选 AT。开发效率最高,能用简单的绝不搞复杂。
-
总结一句话:
能用 AT 解决的别折腾;
涉及钱 的请勤快点写 TCC;
涉及长链路 或异构系统 的,请拥抱 Saga。
作者:资深 AI 与数据架构技术专家 | 专注大数据与高并发架构 | 欢迎关注评论交流