一、Seata AT 模式(自动补偿型)
🔍 核心原理
- 本质 :改进型两阶段提交(2PC) ,但将协调逻辑下沉到 数据源代理层,避免传统 2PC 的阻塞问题。
- 关键机制 :
- 第一阶段(Prepare) :
- 执行业务 SQL(如
UPDATE account SET balance = 100) - Seata 的
DataSourceProxy自动解析 SQL,生成 before image(修改前快照) 和 after image - 将 undo log 与业务数据 在同一个本地事务中提交(保证原子性)
- 执行业务 SQL(如
- 第二阶段(Commit / Rollback) :
- Commit:异步删除 undo log(无实际操作,快速完成)
- Rollback :利用 before image 自动生成反向 SQL (如
UPDATE account SET balance = old_value WHERE id = ?)执行回滚
- 第一阶段(Prepare) :
✅ 关键创新 :第一阶段就提交本地事务,不持有 DB 锁,极大提升并发能力(相比传统 2PC)。
⚖️ 优点
- 对业务零侵入 :只需加
@GlobalTransactional注解 - 自动回滚:无需开发者写补偿逻辑
- 支持主流 ORM(MyBatis、JPA)和微服务框架(Spring Cloud、Dubbo)
⚠️ 缺点
- 仅支持关系型数据库(需能解析 SQL 生成 undo log)
- 隔离性弱:第一阶段提交后,其他事务可读到"中间状态"(需配合全局锁或业务设计规避脏读)
- 长事务风险:若全局事务长时间未决,undo log 无法清理,可能影响 GC 或存储
- 性能损耗:额外写 undo log,TPS 下降约 10%~30%
"Seata AT 模式通过 代理数据源 + undo log 实现了自动补偿。它在第一阶段就提交本地事务,避免了传统 2PC 的同步阻塞,但牺牲了部分隔离性。适用于短事务、强一致要求、且全链路使用关系型数据库的场景,比如订单创建与库存扣减。"
二、RocketMQ 事务消息(最终一致性)
🔍 核心原理
- 核心思想 :将分布式事务转化为"本地事务 + 异步消息"的组合 ,通过 Half Message + 状态回查 保证原子性。
- 关键流程 :
- Producer 发送 Half Message(对 Consumer 不可见)
- 执行 本地事务(如写订单表)
- 根据本地事务结果:
- 成功 → 向 Broker 发送 Commit,消息对消费者可见
- 失败 → 发送 Rollback,消息丢弃
- Broker 回查机制 :若未收到 Commit/Rollback,Broker 会定时回调 Producer 的
checkLocalTransaction()方法,查询本地事务状态
✅ 关键保障 :Half Message 与本地事务的原子性 由"先写 Half Message 再执行本地事务" + "回查兜底"共同保证。
⚖️ 优点
- 高性能、高吞吐:消息异步解耦,不阻塞主链路
- 天然支持失败重试、死信队列、流量削峰
- 与业务完全解耦,适合非核心链路
⚠️ 缺点
- 只能保证最终一致性(通常秒级延迟)
- 必须处理消息重复消费(Consumer 需幂等)
- 依赖消息中间件可靠性(如 RocketMQ 集群高可用)
- 无法回滚已发送的消息(一旦 Commit,只能靠补偿)
"我们通过 RocketMQ 事务消息实现最终一致性:先发 Half Message,再执行本地事务,最后 Commit。即使应用崩溃,Broker 也会回查本地状态。这种方式把强一致需求转化为'本地事务 + 幂等消费',在用户注册送券、订单通知等场景中,既保证了可靠性,又避免了分布式事务的性能开销。"
三、TCC(Try-Confirm-Cancel)
🔍 核心原理
- 核心思想 :将分布式事务拆解为三个业务方法 ,由开发者显式控制资源状态:
- Try :尝试执行,预留资源 (如冻结库存、预占额度)→ 不真正消耗资源
- Confirm :确认执行,真正消耗资源 (如扣减库存)→ 幂等、可重试
- Cancel :取消执行,释放预留资源 (如解冻)→ 幂等、可重试
✅ 关键点 :Try 阶段成功后,后续 Confirm/Cancel 必须成功(通过重试 + 幂等保证)。
⚖️ 优点
- 高性能:Try 完成后即可释放 DB 连接,无长锁
- 业务语义精准:可实现"冻结-扣减"等复杂资源控制
- 强一致性(业务层面)
⚠️ 缺点
- 开发成本高:需编写三套逻辑
- 三大陷阱必须处理 :
- 幂等性:Confirm/Cancel 可能被多次调用
- 空回滚:Cancel 在 Try 之前执行(如超时触发 Cancel,但 Try 未完成)
- 悬挂:Try 在 Cancel 之后执行(如网络延迟导致 Try 晚到)
- 对业务侵入性强
"TCC 的本质是 业务层面的两阶段提交。我们在电商下单中用它实现库存预占:Try 冻结库存,Confirm 扣减,Cancel 解冻。虽然开发复杂,但它避免了 Seata AT 的锁表问题,在大促高并发下表现更稳。我们通过 Redis 记录 TCC 事务状态,解决了空回滚和悬挂问题。"
📊 三大模型核心对比(面试速记表)
| 维度 | Seata AT | RocketMQ 事务消息 | TCC |
|---|---|---|---|
| 一致性级别 | 强一致 | 最终一致 | 强一致(业务级) |
| 核心原理 | 代理数据源 + undo log 自动回滚 | Half Message + 本地事务 + 回查 | 业务三阶段(Try/Confirm/Cancel) |
| 是否侵入业务 | 否(注解驱动) | 否(但需幂等) | 是(需写三套逻辑) |
| 性能 | 中(有 undo log 开销) | ⭐⭐⭐⭐⭐(异步) | ⭐⭐⭐⭐(无长锁) |
| 适用数据源 | 仅关系型数据库 | 任意 | 任意 |
| 最大风险 | 脏读、长事务 | 消息重复、延迟 | 空回滚、悬挂、开发复杂 |
| 典型场景 | 订单+库存(短事务) | 通知、日志、营销 | 库存预占、金融交易 |
💡 高级面试加分认知
-
"能不用分布式事务就不用"是第一原则
→ 优先通过 业务设计(如状态机、对账、重试)规避。
-
最终一致性是互联网系统的常态
→ 强一致只用于 资金、库存等核心资源,其余用 MQ + 幂等。
-
Seata AT 不是万能的
→ 长事务、跨 NoSQL、高并发场景慎用。
-
TCC 的难点不在逻辑,而在异常处理
→ 空回滚、悬挂、幂等才是落地关键。
-
所有分布式事务都需要"兜底"
→ 无论哪种模型,都要有 对账任务 + 人工干预通道。
✅ 总结
- Seata AT :自动回滚,简单但有锁
- RocketMQ 事务消息 :异步解耦,最终一致
- TCC :业务可控,高性能但复杂
单机数据库靠 本地事务(ACID) 保证一致性;
分布式系统因 数据分片 + 服务拆分 ,无法用本地事务跨节点协调 → 需要 分布式事务模型 。
但根据 CAP 定理 ,强一致(C)与高可用(A)不可兼得,因此所有模型都是 在一致性、性能、复杂度之间做权衡。