在分布式事务中,Seata 的 AT 模式(Automatic Transaction)是一种基于两阶段提交协议的事务模式。它通过自动生成数据快照(before image
和 after image
),实现了对分布式事务的高效管理。本文将详细解析 Seata 的 AT 模式两阶段过程,以及 Undo Log
和逆向 SQL 的关系。
1. Seata AT 模式简介
Seata 的 AT 模式是一种基于本地数据库事务的自动事务模式,具备以下核心特点:
- 自动化:通过拦截业务 SQL,自动记录事务前后的数据快照(
before image
和after image
)。 - 两阶段性:通过两阶段协议(提交或回滚),保证分布式事务的一致性和隔离性。
AT 模式主要通过事务协调器(Transaction Coordinator, TC)来管理事务的状态和分支协调,客户端通过 Resource Manager(RM)和 Transaction Manager(TM)与协调器交互。
2. AT 模式两阶段过程
2.1 第一阶段:业务 SQL 执行
第一阶段的核心任务是执行业务 SQL,并记录事务前后的数据快照,以便为后续可能的回滚提供依据。具体流程如下:
-
拦截业务 SQL
Seata 拦截应用程序提交的业务 SQL,解析其语义(如表名、操作类型、条件范围等),确定受影响的数据行。 -
保存
before image
在业务 SQL 执行前,从数据库中查询受影响行的状态,并记录为before image
(事务执行前的数据快照)。- 示例:
- SQL:
UPDATE user SET age = 30 WHERE id = 1;
before image
:{ "id": 1, "name": "Alice", "age": 25 }
- SQL:
- 示例:
-
执行业务 SQL
实际执行业务 SQL,对数据库进行更新。例如:- SQL:
UPDATE user SET age = 30 WHERE id = 1;
- 执行后,数据库记录变为:
{ "id": 1, "name": "Alice", "age": 30 }
- SQL:
-
保存
after image
在业务 SQL 执行后,从数据库中再次查询受影响行的状态,并记录为after image
(事务执行后的数据快照)。- 示例:
after image
:{ "id": 1, "name": "Alice", "age": 30 }
- 示例:
-
生成逻辑行锁
Seata 会为受影响的行生成逻辑锁,以防止其他事务对同一行的数据进行修改。
以上操作均在一个本地事务中完成,确保原子性。
2.2 第二阶段:事务提交或回滚
第二阶段根据事务协调器(TC)的决策,决定是提交还是回滚。
2.2.1 提交
- 提交操作:
- 因为第一阶段的业务 SQL 已经提交至数据库,Seata 只需清除
Undo Log
和行锁,完成事务的清理工作。
- 因为第一阶段的业务 SQL 已经提交至数据库,Seata 只需清除
- 提交流程图:
2.2.2 回滚
- 回滚操作:
- 如果事务协调器判定事务失败,Seata 会根据
before image
还原事务执行前的数据状态。 - 脏写校验:
- 首先验证当前数据库的业务数据是否与
after image
一致。 - 如果一致,则没有脏写,可以安全回滚。
- 如果不一致,则存在脏写,需要人工介入处理。
- 首先验证当前数据库的业务数据是否与
- 如果事务协调器判定事务失败,Seata 会根据
- 回滚方式:
- 提取
before image
数据。 - 基于
before image
生成逆向 SQL。 - 执行逆向 SQL 将数据恢复到事务前的状态。
- 提取
3. Undo Log 与逆向 SQL 的关系
3.1 Undo Log 的数据结构
Undo Log
是用于记录事务执行前后的数据快照的日志结构,主要包括:
- 事务信息:全局事务 ID 和本地事务分支 ID。
- 表名:事务涉及的表。
- 受影响的行数据:
before image
:事务执行前的行状态。after image
:事务执行后的行状态。
- 操作类型:记录操作类型(
INSERT
、UPDATE
、DELETE
)。 - 时间戳:记录事务发生的时间。
3.2 Undo Log 的作用
- 快照保存:
before image
:用于回滚事务,恢复数据。after image
:用于脏写校验,确保数据一致性。
- 回滚依据:
- 在回滚时,从
Undo Log
中提取快照,生成逆向 SQL。
- 在回滚时,从
3.3 为什么需要逆向 SQL?
尽管 before image
已经记录了事务前的状态,但直接覆盖数据库是不现实的,原因如下:
-
数据库只能通过 SQL 修改数据
- 数据库本身没有直接应用快照的接口,必须通过 SQL 操作数据。
- 逆向 SQL 是对数据操作的精确描述。
-
还原需要精确性
- 事务操作可能只修改了部分字段。例如:
- SQL:
UPDATE user SET age = 30 WHERE id = 1;
- 逆向 SQL 只需还原
age
字段,而不是覆盖整条记录。
- SQL:
- 事务操作可能只修改了部分字段。例如:
-
操作类型的不同处理
- INSERT:回滚时需要生成
DELETE
SQL 删除记录。 - UPDATE:回滚时需要生成反向的
UPDATE
SQL 恢复字段。 - DELETE:回滚时需要生成
INSERT
SQL 插入记录。
- INSERT:回滚时需要生成
4. Seata AT 模式回滚示例
业务场景
假设数据库中有一张 user
表,初始数据为:
{ "id": 1, "name": "Alice", "age": 25 }
第一阶段:业务 SQL 执行
- SQL:
UPDATE user SET age = 30 WHERE id = 1;
before image
:{ "id": 1, "name": "Alice", "age": 25 }
after image
:{ "id": 1, "name": "Alice", "age": 30 }
第二阶段:回滚
-
提取
before image
:{ "id": 1, "name": "Alice", "age": 25 }
-
生成逆向 SQL:
UPDATE user SET age = 25 WHERE id = 1;
-
执行逆向 SQL:
- 将数据恢复到事务执行前的状态:
{ "id": 1, "name": "Alice", "age": 25 }
- 将数据恢复到事务执行前的状态:
5. 总结
Seata 的 AT 模式通过 Undo Log
记录数据快照(before image
和 after image
),结合两阶段协议实现事务的一致性和回滚功能。在回滚过程中,逆向 SQL 的生成是核心环节:
- Undo Log 提供数据依据:提取事务前状态(
before image
)。 - 逆向 SQL 精确还原数据:根据操作类型生成特定的 SQL 操作。
这种机制不仅满足了分布式事务的隔离性要求,还提高了事务管理的自动化和效率。