Seata实现分布式事务:大白话全剖析(核心讲透AT模式)
Seata 本质是把分布式事务的各种经典方案(2PC、TCC、Saga、XA)做了极致封装和优化的框架,不用你从零写底层逻辑,只需要简单配置和少量注解,就能落地分布式事务。
它的核心设计是拆分全局事务为多个本地事务,由Seata统一协调管理,保证这些本地事务要么全提交、要么全回滚;而且Seata对Java微服务(Spring Cloud/Dubbo)的侵入性极低,这也是它成为中小企业首选的关键。
先讲Seata的3个核心角色(大白话比喻,理解了角色才能懂流程),这是所有模式的基础,记牢这3个,后面的逻辑一眼就能看透:
Seata三大核心角色(必懂)
- TC(Transaction Coordinator):事务协调者 → 全场总指挥
独立的Seata服务端(需要单独部署),负责创建/管理全局事务、分配全局事务ID(XID),协调所有参与者的提交/回滚,是整个分布式事务的“大脑”。 - TM(Transaction Manager):事务管理器 → 事务发起者
就是你的业务入口服务(比如电商下单的「订单服务」),负责向TC开启全局事务,并最终向TC发起「全局提交」或「全局回滚」的请求。 - RM(Resource Manager):资源管理器 → 事务参与者
所有涉及数据操作的服务/数据库(比如下单场景的「库存服务」「支付服务」),负责管理本地事务,向TC注册分支事务(每个RM的本地事务都是一个「分支事务」),并接收TC的指令,执行本地事务的提交/回滚。
核心关联:一个全局事务 = 1个TM发起 + 1个TC协调 + N个RM参与(N个分支事务),所有操作都通过全局唯一的XID关联(XID是分布式事务的“身份证”,微服务调用链中必须透传XID,Seata会自动做这件事)。
重点:Seata最常用的AT模式(自动事务,90%场景用它)
Seata支持AT、TCC、Saga、XA四种模式,其中AT模式是默认、最主流的,也是最贴合日常开发的——几乎无业务侵入(只加一个注解)、性能接近本地事务、自动完成回滚补偿,完美适配互联网高并发场景,下面用大白话讲透它的实现原理(核心是改进版的2PC,解决了原生2PC性能差、锁资源久的问题)。
先给AT模式定调:基于本地事务+undo log的自动两阶段提交,核心创新是第一阶段就执行本地事务并提交,释放数据库锁,第二阶段只做“确认”或“回滚补偿”,彻底解决了原生2PC的性能瓶颈。
前置条件(AT模式必须满足)
- 数据库支持本地事务(MySQL/Oracle/PG等主流数据库都满足);
- 数据库支持行级锁(InnoDB引擎,这是MySQL的默认引擎);
- 必须使用Seata提供的数据源代理(Seata要拦截SQL,生成undo log,自动代理,不用手动改)。
AT模式核心流程(分2个阶段,结合「电商下单」场景:订单服务(TM)+ 库存服务(RM))
全程围绕XID关联,TC全程协调,先上大白话流程,再讲关键细节:
场景铺垫
- TM:订单服务(下单接口加
@GlobalTransactional注解,发起全局事务); - RM1:订单服务的数据库(插入订单记录,分支事务1);
- RM2:库存服务的数据库(扣减库存,分支事务2);
- TC:Seata服务端(总指挥)。
第一阶段:本地事务提交(核心:做真实操作+留“后悔药”)
这是AT模式最关键的一步,所有RM都会执行本地事务并提交,同时生成undo log(后悔药),并向TC注册分支事务,流程如下:
- TM向TC发起「开启全局事务」请求,TC生成全局唯一XID并返回给TM;
- XID随微服务调用链透传(Seata自动做,比如Feign/Dubbo调用时,XID会放在请求头里),所有参与的RM都能拿到XID;
- 订单服务(RM1)执行本地操作:执行
insert 订单SQL,Seata的数据源代理会拦截这个SQL,做3件事:- 「前置快照」:执行SQL前,先查询要操作的数据,保存数据快照(比如订单表的初始状态:无订单);
- 「执行SQL」:真正插入订单记录,完成业务操作;
- 「生成undo log」:把前置快照+当前数据+SQL类型(插入/更新/删除)封装成undo log,写入数据库的undo_log表(Seata自动创建),这就是“后悔药”;
- RM1提交本地事务,并立即释放数据库的行级锁(原生2PC的致命问题就是不提交、不释放锁,AT模式这里直接提交,性能拉满);
- RM1向TC注册「订单分支事务」,告知TC:我这步操作完成了,留了undo log,随时可以回滚;
- 库存服务(RM2)收到带XID的调用请求,重复步骤3-5:扣减库存→生成undo log→提交本地事务→注册库存分支事务到TC。
第一阶段结束:所有RM的本地事务都已提交,数据已经变更,锁全部释放,业务无感知;如果其中任何一个RM执行失败(比如库存不足),直接回滚自己的本地事务,TM感知到后向TC发起「全局回滚」。
第二阶段:全局提交 OR 全局回滚(TC总指挥,只做轻量操作)
第一阶段所有RM都成功后,TM会向TC发起「全局提交」请求;如果有任何一个RM失败,TM发起「全局回滚」请求,TC根据请求指令,向所有RM下发统一命令。
情况1:全局提交(最常见,轻量到几乎无开销)
- TC向所有RM(订单RM、库存RM)下发「全局提交」指令;
- 各RM收到指令后,只做一件事:异步删除自己的undo log(后悔药没用了,删掉占空间);
- RM向TC反馈“提交完成”,所有RM反馈后,TC标记全局事务完成。
为什么这么轻量? 因为第一阶段已经完成了真实的业务操作并提交,第二阶段的提交只是“清理垃圾”,没有任何数据库锁竞争,性能几乎无损耗。
情况2:全局回滚(有错误,吃“后悔药”恢复数据)
这是AT模式的核心补偿逻辑,通过undo log自动回滚数据,全程无需业务代码介入,流程如下:
- TC向所有RM下发「全局回滚」指令,并附带要回滚的分支事务ID;
- 各RM收到指令后,开启本地小事务,执行回滚操作:
- 从undo_log表中根据分支ID查询对应的undo log(前置快照+当前数据);
- 数据校验:对比undo log中的「当前数据」和数据库中真实的「当前数据」,确保数据没被其他事务修改(Seata的乐观锁机制,避免脏回滚);
- 恢复数据:用undo log中的「前置快照」覆盖数据库的当前数据(比如订单RM删除插入的订单记录,库存RM恢复扣减的库存);
- 删除undo log:回滚完成后,删除该条undo log;
- RM提交这个本地回滚事务,向TC反馈“回滚完成”;
- 所有RM回滚完成后,TC标记全局事务回滚成功。
关键:回滚操作是基于本地事务的,快速且无锁竞争,即使个别RM回滚失败,Seata会自动重试,直到成功(保证最终回滚)。
AT模式的核心优势(为什么是90%场景的首选)
- 几乎无业务侵入:只需要在事务入口加
@GlobalTransactional注解,业务代码一行不用改,开发成本极低; - 性能极高:第一阶段就提交本地事务、释放锁,解决了原生2PC的性能瓶颈,接近本地事务的性能;
- 自动回滚补偿:基于undo log自动完成回滚,不用像TCC那样手动写补偿代码;
- 适配高并发:无长期锁、轻量提交,完美适配互联网电商、支付等高并发场景。
Seata其他模式的实现(简单讲,按需选择)
Seata封装了所有经典分布式事务方案,除了AT模式,其他模式都是为了适配特殊场景,核心是Seata帮你处理了底层的协调、重试、幂等、事务上下文传递,你只需要按规范写少量代码,不用从零开发。
1. Seata TCC模式(适配强一致+高并发,需手动写代码)
完全遵循TCC的Try-Confirm-Cancel三步,但Seata做了封装:
- 你只需要为每个业务写3个方法,分别加
@Tcc(主方法)、@Confirm(确认方法)、@Cancel(取消方法)注解; - Seata自动管理事务上下文(XID),协调各服务的Try/Confirm/Cancel执行;
- 自动处理幂等、空补偿、悬挂(TCC的三大坑),不用自己写判断逻辑。
适用场景:AT模式无法覆盖的场景(比如非数据库操作:调用第三方支付接口、扣减缓存库存)。
2. Seata Saga模式(适配长事务+复杂流程,低代码)
专为长流程、多步骤的分布式事务设计,Seata做了两大优化:
- 普通Saga:你写每个步骤的执行方法和补偿方法,Seata按顺序执行,失败则倒序执行补偿;
- 状态机Saga:用JSON/YAML定义事务流程(步骤顺序、分支、重试规则),不用写代码,低代码配置,支持复杂的流程(比如分支、并行、条件判断)。
适用场景:跨境支付、供应链结算、保险理赔等长流程业务(步骤多、耗时久,甚至跨天)。
3. Seata XA模式(原生2PC,强一致,性能差)
完全实现数据库的XA协议(原生2PC),Seata作为协调者,管理各数据库的XA事务:
- 第一阶段:各数据库执行XA prepare(预提交),锁定资源;
- 第二阶段:TC下发XA commit/rollback,各数据库执行正式提交/回滚。
特点:强一致性(数据库层面保证),但性能差、资源锁定久,仅适用于对一致性要求极高的低并发场景(比如银行核心交易)。
Seata实现分布式事务的核心亮点(总结)
Seata之所以能成为Java微服务分布式事务的首选,核心是它解决了传统分布式事务方案的痛点,做了极致的工程化优化:
- 统一协调:通过TC/TM/RM三大角色,把分布式事务拆分为“全局事务+分支事务”,统一协调管理,逻辑清晰;
- 极简开发:主流的AT模式几乎无侵入,只加一个注解,开发成本接近本地事务;
- 性能优化:AT模式的“第一阶段提交+undo log回滚”,彻底解决了原生2PC的性能瓶颈,适配高并发;
- 全场景覆盖:封装AT/TCC/Saga/XA四种模式,从高并发到长事务,从无侵入到手动开发,满足所有分布式事务场景;
- 自动避坑:内置幂等、重试、空补偿、悬挂、脏回滚等机制,不用开发者手动处理分布式事务的各种坑;
- 无缝集成:完美适配Spring Boot/Spring Cloud/Dubbo,支持MySQL/Oracle/PG等主流数据库,配置简单,快速落地。
最简落地Seata AT模式(代码层面,让你有直观认知)
不用复杂配置,只看核心代码,就能知道Seata有多简单(Spring Cloud场景):
1. 入口服务(TM,事务发起者)
只需要在业务入口方法上加@GlobalTransactional注解,就是TM,开启全局事务:
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private StockFeignClient stockFeignClient; // 调用库存服务的Feign客户端
// 下单接口:分布式事务入口,TM
@GlobalTransactional(rollbackFor = Exception.class) // 加这个注解就够了!
@PostMapping("/createOrder")
public String createOrder(@RequestParam Long goodsId, @RequestParam Integer num) {
// 1. 本地操作:创建订单(RM1,订单服务的本地事务)
orderService.createOrder(goodsId, num);
// 2. 调用库存服务:扣减库存(RM2,库存服务的本地事务,XID自动透传)
Boolean reduceResult = stockFeignClient.reduceStock(goodsId, num);
if (!reduceResult) {
throw new RuntimeException("库存扣减失败,全局回滚");
}
return "下单成功";
}
}
2. 参与服务(RM,库存服务)
一行注解都不用加,正常写本地业务代码就行,Seata自动拦截并生成undo log:
@RestController
public class StockController {
@Autowired
private StockService stockService;
// 扣减库存:RM,普通本地接口
@PostMapping("/reduceStock")
public Boolean reduceStock(@RequestParam Long goodsId, @RequestParam Integer num) {
stockService.reduceStock(goodsId, num); // 正常扣减库存的本地方法
return true;
}
}
这就是Seata的威力:业务代码几乎无改动,只加一个注解,就能实现分布式事务的“要么全成、要么全错”。
核心总结
- Seata的核心是拆分全局事务为多个本地事务,通过TC(总指挥)、TM(发起者)、RM(参与者)三大角色协调,用XID关联整个调用链;
- 主流的AT模式是改进版2PC,核心是「第一阶段本地提交+生成undo log,第二阶段轻量提交/基于undo log自动回滚」,无侵入、高性能,适配90%的互联网场景;
- Seata封装了TCC/Saga/XA模式,分别适配强一致高并发、长流程复杂业务、强一致低并发场景,底层自动处理幂等、重试等分布式坑;
- 落地极简单:AT模式只需要在事务入口加
@GlobalTransactional注解,业务代码无改动,完美集成Spring Cloud/Dubbo。
❤️ 如果你喜欢这篇文章,请点赞支持! 👍 同时欢迎关注我的博客,获取更多精彩内容!
本文来自博客园,作者:佛祖让我来巡山,转载请注明原文链接:https://www.cnblogs.com/sun-10387834/p/19584278

浙公网安备 33010602011771号