240807-分布式事务解决方案Seata之AT事务

AT事务模式

在 Seata AT 模式下,分支事务的注册是完全自动的,不需要开发者编写任何注册代码。

一、自动注册的原理

Seata 通过 数据源代理 (DataSource Proxy) 和 SQL 拦截 技术实现自动注册。

流程如下:

  1. 业务代码执行 SQL:
    你的代码正常调用 mapper.insert() 或 jdbcTemplate.update()。
  2. Seata 拦截:
    Seata 的 DataSourceProxy 拦截了数据库连接。在执行 SQL 前,它会检查当前线程上下文 (RootContext) 中是否有 XID。
  3. 自动注册:
    如果有 XID:Seata 认为这是一个全局事务的一部分。它会自动向 Seata Server (TC) 发起“分支事务注册”请求,获取 Branch ID。
    如果没有 XID:Seata 认为这是普通本地事务,直接执行 SQL,不注册分支。
  4. 执行与汇报:
    执行 SQL -> 记录 undo_log -> 提交本地事务 -> 自动向 TC 汇报分支状态(Phase 1 完成)。

二、TCC代码实战

2.1数据库初始化

在各个微服务中,创建 undo_log表

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE TABLE `undo_log` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`branch_id` BIGINT(20) NOT NULL,
`xid` VARCHAR(100) NOT NULL,
`context` VARCHAR(128) NOT NULL,
`rollback_info` LONGBLOB NOT NULL,
`log_status` INT(11) NOT NULL,
`log_created` DATETIME NOT NULL,
`log_modified` DATETIME NOT NULL,
`ext` VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.2配置依赖

各个微服务引入

1
2
3
4
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>

2.3代码入口添加全局事务

1
2
3
4
5
@GlobalTransactional
@Override
public void process(EventMessageReq eventMessageReq) {
deviceEventService.processDeviceEvent(eventMessageReq);
}

2.4接口测试

发送测试报文,可以看到seata server 日志信息

测试报文

三、什么时候“不会”自动注册

如果你发现日志中没有分支注册记录,或者事务不回滚,通常是以下原因导致自动注册失败:

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

Update your browser to view this website correctly. Update my browser now

×