AT事务模式
在 Seata AT 模式下,分支事务的注册是完全自动的,不需要开发者编写任何注册代码。
一、自动注册的原理
Seata 通过 数据源代理 (DataSource Proxy) 和 SQL 拦截 技术实现自动注册。
流程如下:
- 业务代码执行 SQL:
你的代码正常调用 mapper.insert() 或 jdbcTemplate.update()。 - Seata 拦截:
Seata 的 DataSourceProxy 拦截了数据库连接。在执行 SQL 前,它会检查当前线程上下文 (RootContext) 中是否有 XID。 - 自动注册:
如果有 XID:Seata 认为这是一个全局事务的一部分。它会自动向 Seata Server (TC) 发起“分支事务注册”请求,获取 Branch ID。
如果没有 XID:Seata 认为这是普通本地事务,直接执行 SQL,不注册分支。 - 执行与汇报:
执行 SQL -> 记录 undo_log -> 提交本地事务 -> 自动向 TC 汇报分支状态(Phase 1 完成)。
二、TCC代码实战
2.1数据库初始化
在各个微服务中,创建 undo_log表
1 | CREATE TABLE `undo_log` ( |
2.2配置依赖
各个微服务引入
1 | <dependency> |
2.3代码入口添加全局事务
1 |
|
2.4接口测试
发送测试报文,可以看到seata server 日志信息

三、什么时候“不会”自动注册
如果你发现日志中没有分支注册记录,或者事务不回滚,通常是以下原因导致自动注册失败:
- 手动创建了 DataSource
如果你没有使用 Spring Boot 的自动配置,而是手动 new DataSource() 或者在某些配置类中覆盖了 DataSource Bean 且没有包裹 DataSourceProxy,Seata 无法拦截 SQL。 - 多数据源场景
如果使用 DynamicDataSource 或多数据源切换,Seata 可能无法识别所有数据源。
解决:需要配置 SeataAutoDataSourceProxyCreator 或手动将所有数据源包装为 DataSourceProxy。 - XID 丢失 (最常见)
分支事务注册的前提是“知道自己是哪个全局事务的一部分”。如果 XID 没了,就不会注册。
场景:
在 @GlobalTransactional 方法内开了新线程 (new Thread())。
自定义 Feign/Dubbo 拦截器没透传 Root-Context。
消息队列消费端没有手动绑定 XID。
现象:下游服务执行 SQL 正常,但 TC 上没有分支记录,上游回滚时下游不回滚。 - 非数据库操作
分支事务是基于数据库资源的。
如果你在事务中只调用了 Redis、MongoDB 或 HTTP 接口,不会注册分支事务。
Seata AT 模式目前主要支持关系型数据库 (MySQL, Oracle, PG 等)。Redis 需要配合其他方案(如 TCC 或 消息最终一致性)。