Seata AT 模式简单学习及总结

一、基础概念:TM、RM、TC

Seata 分布式事务核心三角色,定义缩写:

  1. TC (Transaction Coordinator,事务协调器)
    全局事务中枢,独立服务,全局事务管家
  • 记录全局事务状态、全局锁
  • 接收 TM 开启 / 提交 / 回滚指令,通知所有 RM 分支提交或回滚
  • 存储全局事务、分支事务日志(Seata Server 就是 TC)
  1. TM (Transaction Manager,事务管理器)

    全局事务发起方,通常是入口服务(Controller / 调用入口)

  • 开启全局事务 @GlobalTransactional
  • 向 TC 申请创建全局事务、注册全局 ID (XID)
  • 所有分支执行完后,决定全局提交 / 全局回滚,发给 TC
  1. RM (Resource Manager,资源管理器)

    分支事务参与者,每个数据库对应一个 RM

  • 管理本地分支事务,向 TC 注册分支、上报分支执行状态
  • 执行分支提交、分支回滚,处理全局锁、undo_log、行锁
  • 每个微服务操作自己数据库时,就是一个 RM

XID:全局事务唯一 ID,贯穿整个分布式链路,所有分支都携带同一个 XID 关联全局事务。

二、AT 模式是什么?

AT(Automatic Transaction)自动事务模式 ,Seata 默认主流模式,无侵入、基于本地事务 + 补偿回滚 ,对业务代码改动极小,仅需注解 @GlobalTransactional

核心底层原理:两阶段提交(2PC)改造版 ,利用undo_log(回滚日志)、global_lock(全局锁)保证最终一致性 ,隔离级别默认读未提交,可做防脏写。

AT 模式 第一阶段(准备阶段:执行业务 SQL,提交本地事务,预留回滚)

完整步骤:

  1. TM 开启全局事务,向 TC 请求生成全局 XID,绑定到当前调用链路。
  2. 微服务 RM 执行业务 DML(update/insert/delete)前,先查询当前数据快照 ,生成before_image(修改前数据镜像)
  3. RM 执行业务 SQL 修改数据,生成after_image(修改后数据镜像)
  4. 同一个本地事务 内:
    • 执行业务 SQL 更新业务表
    • 插入一条 undo_log 记录(存储 before/after 镜像、XID、主键)
    • 向 TC 注册当前分支事务
  5. 提交本地数据库事务,释放本地行锁,此时数据已经改到数据库,但并未全局生效。
  6. RM 向 TC 上报:本分支第一阶段执行成功。

关键点:一阶段就提交本地事务,性能远优于传统 XA;undo_log 是后续回滚的补偿依据。

AT 模式 第二阶段:两种分支走向(提交 / 回滚)

场景 1:全局正常提交(所有分支一阶段都成功)
  1. TM 判断全部分支执行无误,向 TC 发起全局提交指令。
  2. TC 通知所有参与该 XID 的 RM 执行分支提交。
  3. RM 收到提交指令:直接删除自身对应的 undo_log 记录,不需要修改业务数据(一阶段数据已经落库)。
  4. RM 上报分支提交完成,TC 标记全局事务完结,释放全局锁。

为什么不用改业务数据?一阶段本地事务已经把数据改完了,提交只是清理回滚日志。

场景 2:全局回滚(任意分支异常、超时、抛出异常)
  1. TM 捕获异常,向 TC 发起全局回滚指令。
  2. TC 通知所有 RM 执行分支回滚。
  3. RM 查询当前 XID 对应的 undo_log,对比当前数据库最新数据与 after_image:
    • 数据未被其他事务修改:用 before_image 反向执行补偿 SQL,恢复原始数据
    • 数据已被修改(脏写冲突):触发锁等待 / 回滚报错,保证数据一致性
  4. 补偿 SQL 执行完成,删除 undo_log,提交本地补偿事务。
  5. RM 上报回滚完成,TC 标记全局事务回滚结束,释放全局锁。

AT 两大核心机制(解决数据一致性 + 并发脏写)

  1. Undo Log 回滚日志

    补偿回滚基石,一阶段同步写入,二阶段提交删除、回滚执行逆 SQL。

  2. 全局锁(Global Lock)

    解决并发修改同一行数据脏写问题:一阶段修改数据后占用全局锁,其他事务修改该行会被阻塞,直到当前全局事务二阶段完成释放锁。

三、TM、TC、RM 生动生活化案例(下单扣库存扣余额)

业务场景

用户下单:

服务 A(订单服务 TM)→ 创建订单

服务 B(库存服务 RM1)→ 扣商品库存

服务 C(账户服务 RM2)→ 扣用户余额

三个服务三个数据库,必须要么全部成功,要么全部回滚,用 Seata AT 保证分布式一致。

TC = 小区物业总管;TM = 发起办事的业主;RM = 两家门店

角色对应
  • TC(物业总管):登记整件事台账,统筹决定整件事办成功还是作废,通知两家门店执行收尾
  • TM(下单服务 / 业主):发起 "下单扣款减库存" 整件事,事情出问题就通知总管全部撤销
  • RM1(库存门店)、RM2(账户门店):各自处理自己业务,听总管指令收尾

完整分步协作流程

一阶段(分头办事,各自留反悔凭证)
  1. TM(下单服务)找到 TC:帮我开一个全局办事单号 XID,我要发起一笔分布式下单事务。TC 登记全局事务,生成 XID。
  2. TM 调用库存服务 RM1:
    • RM1 查库存原有数量(before 镜像),扣减库存(after 镜像)
    • 在自己库存库同一个本地事务:改库存 + 写 undo_log(反悔凭证)
    • 向 TC 登记:我是分支 1,XID 这件事我一阶段办完了
    • 提交库存本地事务,库存数据真实变少,本地锁释放
  3. TM 继续调用账户服务 RM2:
    • RM2 查用户原有余额(before 镜像),扣减余额(after 镜像)
    • 账户库同一个本地事务:扣余额 + 写 undo_log 反悔凭证
    • 向 TC 登记:我是分支 2,XID 这件事我一阶段办完了
    • 提交账户本地事务,余额真实变少
  4. TM 汇总:两个分支全部一阶段执行成功,等待最终决策。
二阶段情况 1:全部正常 → 全局提交
  1. TM 告诉 TC:整件事没问题,全局提交。

  2. TC 下发指令给 RM1、RM2:你们各自收尾。

  3. RM1 删掉自己库存库 undo_log(反悔凭证作废);RM2 删掉账户库 undo_log。

  4. TC 标记整个全局事务完成,释放全局锁。

    最终结果:订单创建、库存扣减、余额扣减,全部生效,数据一致。

二阶段情况 2:扣余额时报异常(余额不足抛异常)→ 全局回滚
  1. RM2 执行报错,异常向上抛到 TM。

  2. TM 立刻通知 TC:整件事作废,全局回滚。

  3. TC 给 RM1、RM2 下发回滚指令。

  4. RM2 通过 undo_log 里修改前余额数据,执行补偿 SQL,把扣掉的余额加回去,删除 undo_log。

  5. RM1 通过 undo_log 原来库存数据,把扣掉的库存加回去,删除 undo_log。

  6. TC 标记全局事务回滚结束,释放全局锁。

    最终结果:订单创建回滚删除、库存不变、余额不变,三方数据全部还原,满足最终一致性。

四、Seata 其他三种模式简要对比(XA / TCC / SAGA)

1. XA 模式(传统数据库两阶段,强一致性)

  • 原理:数据库原生支持 XA 协议,RM 是数据库 XA 驱动,一阶段锁定资源预提交,二阶段统一提交 / 回滚
  • 优点:无业务侵入,强一致性
  • 缺点:一阶段长时间占用行锁,并发性能极差,MySQL 等数据库兼容性一般
  • 适用:低并发、对一致性要求极高的传统内部系统

2. TCC 模式(侵入式手动补偿,高性能)

TCC = Try-Confirm-Cancel,业务代码手写三阶段逻辑

  1. Try:预留资源(冻结库存、冻结余额)
  2. Confirm:确认扣减,正式提交
  3. Cancel:释放预留资源,回滚补偿
  • 优点:不依赖 undo_log,无数据库锁阻塞,性能最好,自由度最高
  • 缺点:侵入极强,每个接口都要手写三套逻辑,开发维护成本极高
  • 适用:高并发核心交易、金融支付场景

3. SAGA 模式(长事务、柔性事务,反向补偿)

  • 正向:每个业务步骤正常执行;任一失败,反向执行前面所有步骤的补偿业务接口
  • 无锁设计,无预留阶段,适合长流程分布式事务(订单履约、物流、审批长链路)
  • 优点:适合超长事务、跨异构系统(非数据库)
  • 缺点:仅保证最终一致性,存在中间数据脏数据,无隔离性,补偿逻辑容易写乱

四种模式极简总结表格

模式 侵入性 一致性 性能 核心原理
AT 极低(注解) 最终一致 undo_log 自动补偿 + 全局锁
XA 无侵入 强一致 数据库原生 XA 两阶段锁
TCC 极高(手写三接口) 最终一致 最优 手动预留 + 确认 / 撤销
SAGA 中(写补偿接口) 最终一致 良好 失败逆向补偿
相关推荐
rebibabo5 小时前
Java基础(番外) | Kafka 入门:分区、副本与消费者组原理
java·分布式·kafka·学习笔记·副本·分区·异步日志
swg3213217 小时前
Kafka基于ZK和KRaft的设计原理与差异
分布式·kafka
gb448oww58 小时前
Redis分布式锁进阶第三十五篇
数据库·redis·分布式
2601_962440849 小时前
计算机毕业设计之jsp教室管理系统
java·开发语言·笔记·分布式·算法·课程设计·推荐算法
无小道15 小时前
Redis——主从复制
数据库·redis·分布式·主从
风吹夏回17 天前
RabbitMQ 核心术语 + Python pika 方法完整讲解
分布式·python·rabbitmq
风吹夏回18 天前
RabbitMQ 三种模式入门:HelloWorld、WorkQueue、PubSub
分布式·rabbitmq·ruby
霸道流氓气质18 天前
分布式追踪与 RequestId 传播完全指南
分布式
cheems952718 天前
[RabbitMQ高级特性] 消息确认机制:从 Ready / Unacked 到 basicAck、basicReject、basicNack 的底层拆解
分布式·rabbitmq·ruby