分布式事务Seata

之前一直只是使用@GlobalTransactional 注解在业务方法上,但是没有从底层去了解,今天花一点时间更新一下Seata分布式事务。
首先是框架回滚做了什么

1.AT模式

核心一句话:**一阶段提前提交业务 SQL,同时存 undo_log 快照;二阶段回滚就是用 undo_log 里的前镜像做补偿 SQL 还原数据

✅ 一阶段:Prepare(准备)

关键点:业务数据 和 undo_log 在同一个本地数据库事务内一起提交

  1. RM 代理拦截业务 SQL,执行 SQL 前查询修改前数据:beforeImage(前镜像)
  2. 执行业务 SQL(update/insert/delete)修改业务表
  3. 执行 SQL 后查询修改后数据:afterImage(后镜像)
  4. 将 beforeImage、afterImage、xid、branchId 写入undo_log 回滚日志表
  5. 业务数据变更 + undo_log,在同一个本地事务一起提交到数据库
  6. 向 TC 申请该行数据的全局锁;拿到锁成功,本地数据库锁、数据库连接直接释放
  7. RM 上报 TC:本分支一阶段执行成功

✅ 二阶段有两种分支结果:全局提交 / 全局回滚

1)全局提交(正常成功)

  • TM 通知 TC:全局事务提交
  • TC 下发 commit 指令给各个 RM 分支
  • RM 收到 commit:只删除本分支对应的 undo_log 记录,不需要修改业务数据
  • 官方特性:二阶段提交异步化,非常快,不阻塞业务。

2)全局回滚(分支异常、抛出异常、事务超时)

  1. TM 通知 TC 执行全局回滚
  2. TC 向所有参与的 RM 下发 rollback 指令
  3. RM 根据XID+branchId查询 undo_log 快照
  4. 脏写校验:拿 undo_log 里面保存的afterImage 和 当前数据库真实数据对比
    • 相等:期间没有别的事务修改这条记录,可以安全补偿回滚
    • 不相等:发生脏写,Seata无法自动回滚,输出告警,需要人工介入处理
  5. 根据 beforeImage 自动生成反向补偿 SQL
    • update → 反向 update 还原旧值
    • insert → delete 删除新增数据
    • delete → insert 把旧数据插回去
  6. 在全新的本地数据库事务中执行补偿 SQL + 删除 undo_log,保证这两步原子性
  7. RM 把回滚结果上报 TC

补偿 SQL 执行会做幂等,TC 会重试 rollback 指令,不怕网络抖动重复下发。

Seata AT 模式:非侵入式分布式事务,业务几乎不用改代码,只加注解,底层代理 JDBC 数据源实现

  1. 业务不能直接使用原生 DataSource,必须被 Seata 的 DataSourceProxy 包装
  2. 代理拦截 JDBC 的增删改 SQL(insert/update/delete),自动做三件事:
    • 查询数据快照(beforeImage、afterImage)
    • 写入 undo_log 回滚日志
    • 校验、抢占全局锁
  3. 业务代码不需要手写任何回滚逻辑,全部代理层自动完成。
    MyBatis、JdbcTemplate、MyBatis‑Plus 都可以直接兼容,不需要改 DAO。

隐含坑点:

  1. undo_log 必须和业务表同一个库,否则本地事务失效;
  2. 数据源忘记包装 DataSourceProxy,分布式事务直接失效;
  3. 本地@Transactional和@GlobalTransactional可以一起用,本地事务嵌套在分布式分支里;
  4. XID 必须跨服务传递,自定义 http 调用需要手动传递 XID,Feign/Dubbo 自动处理;
  5. 二阶段回滚出现脏写报错,业务无法自动恢复,需要告警人工修复;
  6. TC(Seata‑Server)建议集群部署保证高可用。

2. TCC 模式(Try-Confirm-Cancel)

✅ 没有 undo_log!完全没有快照表
✅ 回滚载体:你自己编写的 cancel() 方法
✅ 回滚执行者:Seata 框架调用你写的 Cancel 接口
✅ 流程:

  1. Try:预留资源(冻结余额、锁定库存)
  2. Confirm:确认提交(真正扣减)
  3. Cancel:回滚释放资源(解冻、释放库存)
    ✅ 特点:业务侵入高,所有补偿逻辑自己写
    ✅ 要自己解决三大经典问题:空回滚、悬挂、幂等
    ✅ 优势:不受数据库限制,可以对接外部支付、第三方接口、不支持 AT 的存储

举例子:Try 冻结 100 元;全局失败 → 调用 Cancel 把冻结金额释放回去

3. SAGA 模式(长事务模式)

✅ 也没有 undo_log,也没有 Try
✅ 模型:一串正向业务步骤 + 每一步配套一个补偿接口
✅ 回滚载体:预先定义好的 compensation 补偿接口
✅ 回滚执行者:Seata 编排器,反向依次执行补偿接口

正向:A → B → C
如果 C 失败,回滚顺序:C 补偿 → B 补偿 → A 补偿(逆序)
✅ 适合:流程很长、跨很多异构服务、耗时久的业务(订单履约、物流)
✅ 缺点:没有锁机制,隔离性差,容易并发脏数据;补偿逻辑业务开发负责

4. XA 模式

✅ 不需要 undo_log,不需要业务写补偿代码
✅ 回滚载体:数据库原生 XA 事务能力
✅ 回滚执行者:数据库本身
✅ 流程:

  1. 一阶段 prepare:数据库锁住资源,不提交
  2. TC 通知回滚 → 数据库执行原生 rollback
    ✅ 优点:强一致,数据库原生保证
    ✅ 缺点:一阶段持有数据库锁、连接,性能差;数据库必须支持 XA 协议
posted @ 2026-10-24 14:04  iUv~  阅读(15)  评论(0)    收藏  举报