---
title: Seata AT 模式实现原理
type: concept
domain: distributed-transaction
tags: [distributed-transaction, seata, at-mode, global-lock, undo-log, tc, tm, rm, xa, cloud-native]
status: learning
created: 2026-09-23
last_reviewed: 2026-10-10
method: feynman
related_questions:
  - "Seata 的 AT 模式的实现原理"
  - "MySQL 的 XA 事务在微服务架构中的挑战 & Seata AT 对 2PC 的关键改进"
related_knowledge:
  - ./distributed-tx-overview.md
  - ./2pc-3pc.md
  - ./tcc-pitfalls.md
  - ./cross-border-payment-design.md
  - ../mysql/mysql-transaction-core.md
anki_cards: 12
interview_rounds:
  - "2026-09-23-round-2-Q5"
  - "2026-10-10-round-1-Q9"
---

# Seata AT 模式实现原理

> Seata AT 是 Apache Seata 提供的"自动补偿"模式，核心思想是"让业务代码无感知地享受分布式事务"，靠框架代理数据源和 undo_log 实现。全局锁是 AT 模式的灵魂。

## TL;DR（30 秒扫完）

- **三角色**：TC（Seata Server，协调全局事务）+ TM（业务应用代理）+ RM（代理 DataSource）
- **一阶段**：拦截 SQL → 读 before image → 执行业务 SQL → 读 after image → 同本地事务写 undo_log → 申请全局锁 → 本地提交
- **二阶段成功**：异步删除 undo_log；**二阶段失败**：读 undo_log → 生成反向 SQL → 本地回滚
- **全局锁是灵魂**：一阶段释放本地锁但保留全局锁到二阶段结束，防止中间态被改
- **与 2PC 关键区别**：一阶段提交后释放本地锁，参与者不阻塞
- **性能瓶颈**：全局锁按行加锁，高并发同一行会串行化

## 关键结论

- **结论 A**：AT 模式的灵魂是全局锁——一阶段释放本地锁但保留全局锁，让事务不阻塞
- **结论 B**：undo_log 是回滚的依据，存 before/after image（JSON 格式）
- **结论 C**：代理数据源让业务代码完全无感，框架自动拦截 SQL
- **结论 D**：全局锁是高并发场景的性能瓶颈，需要换 TCC 才能解决

## 完整讲解（费曼四步）

### STEP 1 · 概念

**Seata AT 模式**：Apache Seata 提供的"自动补偿"分布式事务模式，框架代理数据源，业务代码基本不用改，靠 undo_log 实现自动回滚。

### STEP 2 · 大白话

**单机事务类比**：你去银行柜台办业务，柜员帮你把所有步骤办完，你不用管中间过程——引擎自己保证。

**Seata AT 类比**：你同时要办"开户+转账+理财"三件事，分别找三个柜员。AT 模式相当于有一个"协调秘书"：
- 秘书让三个柜员各自先把业务"预演"一遍（读 before image → 执行 → 读 after image），并把"操作记录"写下来（undo_log）
- 秘书同时给每个柜员的业务盖一个"全局章"（全局锁），防止别人在中间修改
- 如果三个柜员都说"没问题"，秘书让所有人正式提交，然后把操作记录删掉
- 如果有一个柜员说"有问题"，秘书让所有人按操作记录"反向操作"回滚

### STEP 3 · 底层

#### 三角色架构

| 角色 | 英文 | 职责 | 实现 |
|------|------|------|------|
| **TC** | Transaction Coordinator | Seata Server，协调全局事务，维护全局事务状态 | Seata Server 进程 |
| **TM** | Transaction Manager | 业务应用内的代理，发起全局事务、决定提交或回滚 | 业务应用中的代理类 |
| **RM** | Resource Manager | 代理 DataSource，管理分支事务，与 TC 通信 | JdbcProxy 拦截 SQL |

#### AT 模式两阶段流程

```
一阶段（本地事务阶段）：
  业务 SQL 执行：
    1. 拦截 SQL，读取业务数据前镜像（before image）
    2. 执行业务 SQL
    3. 读取业务数据后镜像（after image）
    4. 在同一本地事务内：业务 SQL + 写 undo_log（存 before/after image）
    5. RM 向 TC 申请**全局锁**（行级锁）
    6. 本地事务提交（业务数据和 undo_log 一起落盘）

二阶段（全局事务阶段）：
  成功路径：TC 让各 RM 异步删除 undo_log
  失败路径：TC 让各 RM 读 undo_log，反向生成回滚 SQL，本地事务回滚
```

#### 全局锁的作用（AT 模式的灵魂）

- **目的**：防止一阶段提交后、二阶段提交前，其他事务修改了同一行数据
- **实现**：基于行级锁，TC 记录 lock_record 表
- **代价**：全局锁存在期间，同一行不能有其他事务修改，影响并发性能
- **关键区别**：一阶段提交后**本地锁释放**（不阻塞本地事务），但**全局锁保留**到二阶段结束

#### undo_log 的作用

- Seata 框架自动创建的表（业务需手动建表，DDL 见官方文档）
- 存 before/after image（JSON 格式）
- 回滚时框架自动读取 undo_log，生成"反向 SQL"（如 `UPDATE t SET col = 'old_value' WHERE id = 1`）

#### 代理数据源的无感机制

- 业务配置 SeataDataSourceProxy 替换原 DataSource
- 所有 SQL 都被 JdbcProxy 拦截
- 业务代码完全无感知

#### 与 2PC / TCC / XA 的对比

| 维度 | 2PC/XA | Seata AT | TCC |
|------|--------|----------|-----|
| 侵入性 | 低 | **低** | 高 |
| 一致性 | 强 | 强 | 强 |
| 阻塞 | 会 | **不阻塞**（一阶段后释放本地锁） | 不阻塞 |
| 锁机制 | 行锁（数据库级） | **全局锁（Seata 级）** | 业务锁 |
| 回滚方式 | 数据库 redo log | **undo_log（业务层）** | 业务代码 |

#### 全局锁性能瓶颈

- 全局锁按行加锁，一阶段提交后立即释放本地锁但保留全局锁到二阶段结束
- 高并发同一行会串行化
- 优化方案：缩短事务、批量提交、换 TCC（TCC 的锁是业务层自己实现的，粒度更细）

#### 生产部署要点

- 建好 undo_log 表
- 配好 Seata Server 高可用（多 TC 实例 + 注册中心）
- 监控全局锁占用情况
- 设置事务超时时间（默认 15 分钟）
- 避免 TC 故障导致事务长期悬挂

### STEP 3.5 · 与 2PC / XA 的深度对比（AT 对 2PC 的三大关键改进）

> AT 不是"2PC 的补丁"，而是**重新拆两阶段**——一阶段业务已经提交，二阶段只做日志清理或补偿。这是 AT 在微服务/云原生场景下的核心竞争力。

#### XA 在微服务架构下的六大工程挑战

XA 是 2PC 的具体实现（MySQL 提供 `XA START/PREPARE/COMMIT` 语法），在微服务场景下有六大痛点：

| # | 挑战 | 说明 | 工程后果 |
|---|------|------|---------|
| 1 | **会话耦合** | XA 事务要求事务内保持同一 DB 连接 | 跨服务不同 DB 实例无法天然延伸 |
| 2 | **长事务阻塞** | PREPARE 到 COMMIT 期间所有参与者行锁+连接都被持有，跨网络调用可能持续秒级/几十秒 | 连接池打满，QPS 上不去 |
| 3 | **协调者阻塞** | TC 在 Prepare 之后 Commit 之前崩溃，RM 进入"不确定状态"（2PC 经典问题） | 事务永久悬挂 |
| 4 | **性能瓶颈** | 所有参与者 DB 连接在整个事务期间不释放 | QPS 差 |
| 5 | **跨库兼容** | Oracle/PostgreSQL/SQL Server 的 XA 实现不完全一致 | 微服务异构场景难统一 |
| 6 | **扩展性差** | 单个 XA 事务 RM 数量通常不超过 3-4 个 | 跨多个微服务的链路覆盖不了 |

**本质问题**：XA 是"两阶段都要执行操作"——一阶段加锁不提交，二阶段提交或回滚。所有参与者的资源在整个事务期间都被占用。

#### Seata AT 相对 2PC 的三大关键改进

| 维度 | 2PC / XA | **Seata AT** | 关键差异 |
|------|---------|-------------|---------|
| **一阶段动作** | 加锁 + 不提交 | **业务提交 + undo_log** | AT 一阶段业务已经提交，本地锁立即释放 |
| **二阶段动作** | 提交或回滚（执行操作） | **清理或补偿**（读 undo_log） | AT 二阶段是记账，不再执行操作 |
| **回滚方式** | TC 通知 RM 反向操作 | **读 undo_log 生成反向 SQL** | AT 回滚基于日志，业务方完全不参与 |
| **锁粒度** | 数据库行锁全程持有 | **业务本地事务提交后释放，TC 侧逻辑锁** | AT 全局锁只在跨全局事务冲突检测时使用 |
| **业务侵入** | 低（配置 XA） | **更低（配置代理数据源即可）** | 业务代码不用改一行 |

**核心洞察**：AT 的两大创新——
1. **两阶段拆分解耦**：一阶段"业务提交"，二阶段"日志清理"，与 2PC "两阶段都执行操作"完全不同
2. **基于日志的自动补偿**：不需要业务方参与回滚，TC 读 undo_log 自动生成反向 SQL

**云原生适配能力**（AT 相对 XA 的额外优势）：

| 维度 | 说明 |
|------|------|
| **TC 无状态可水平扩展** | K8s Operator 部署，多 TC 实例通过 Raft 或共享存储协调 |
| **RM 无状态可重启** | 业务进程重启后，TC 通过**事务回查**机制恢复未完成事务 |
| **支持多种资源** | 不只是 MySQL，还有 Redis / RocketMQ / Kafka 等适配 |
| **业务无侵入** | JDBC 代理自动拦截 SQL，业务代码不用改 |
| **容器化友好** | 官方 K8s Operator，通过 service discovery 找 TC |

#### AT 的局限（选型时必须知道）

- **热点行场景全局锁竞争严重**：全局锁按行加锁，高并发同一行串行化
- **非事务性操作无法覆盖**：RPC 调用（发消息、发邮件）需要额外的 TCC 或事务消息
- **依赖数据库唯一索引**：全局锁基于数据库行锁，需要业务表有合理的主键/索引
- **主要面向 Java 生态**：非 Java 服务支持较弱
- **不适合跨语言异构**：跨语言需自行实现事务回查

#### 工程选型建议

- **主链路强一致（订单+库存）** → Seata AT 或 TCC
- **核心账务（扣款+入账）** → TCC 或 XA
- **副链路最终一致（通知/积分/风控）** → 事务消息 / 本地消息表
- **跨 RPC 调用** → 事务消息 / TCC（AT 覆盖不了）

### STEP 4 · 简化

> **一句话总结**：Seata AT = 代理数据源 + undo_log + 全局锁，让业务代码无感地享受分布式事务；全局锁是灵魂但不阻塞，高并发场景换 TCC。

## 常见误区（从面试记录提炼）

- **误区 1**："AT 模式不需要全局锁" → 正确：全局锁是 AT 模式的**灵魂**，没有它就无法保证一致性
- **误区 2**："AT 模式和 2PC 一样会阻塞" → 正确：AT 一阶段提交后释放本地锁，不阻塞本地事务；2PC 是全程持锁
- **误区 3**："undo_log 是数据库自带的" → 正确：undo_log 是 Seata 框架自定义的表，业务需手动建表
- **误区 4**："AT 模式完全无侵入" → 正确：AT 模式侵入性低（业务代码不用改），但仍需配置代理数据源和建 undo_log 表
- **误区 5**："Seata 叫 STAY" → 正确：**Seata**（Apache 项目，S-e-a-t-a）
- **误区 6**："AT 模式是保持会话" → 正确：AT 的核心是**业务无侵入 + 全局锁 + undo log 自动补偿**，与"保持会话"（那是 XA）完全不同
- **误区 7**："AT 模式不需要 undo_log" → 正确：undo_log 是 AT 二阶段回滚的**唯一依据**，没有 undo_log 就无法做反向 SQL 补偿
- **误区 8**："XA 在微服务下可以直接用" → 正确：XA 在微服务下有 6 大挑战（会话耦合、长事务阻塞、协调者阻塞、性能瓶颈、跨库兼容、扩展性差），工程上被 Seata AT/TCC 替代
- **误区 9**："AT 的三大改进只是加了事务" → 正确：AT 相对 2PC 的三大改进是**两阶段拆分解耦**（一阶段业务提交+undo_log、二阶段清理/补偿）+ **基于日志自动补偿**（业务方不参与回滚）+ **全局锁优化锁粒度**（业务提交后释放本地锁）

 ## 延伸追问（面试追问预演）

 1. **"Seata AT 的全局锁，会不会成为性能瓶颈？怎么优化？"**
    - 要点：全局锁按行加锁，一阶段提交后立即释放本地锁但保留全局锁到二阶段结束；高并发同一行会串行化。优化：缩短事务、批量提交、换 TCC

 2. **"undo_log 表会无限增长吗？怎么清理？"**
    - 要点：二阶段成功后异步删除；TC 有定时清理任务；如果 TC 故障，undo_log 会滞留，需要人工清理或恢复 TC 后自动清理

 3. **"Seata AT 支持非 MySQL 数据库吗？"**
    - 要点：支持 PostgreSQL、Oracle、SQL Server 等，但需要各自方言的 undo_log 生成逻辑；MyCAT 等分库分表中间件有特殊适配

 4. **"AT 模式和 TCC 模式怎么选？"**
    - 要点：低侵入+快速落地→AT；高可控+可审计→TCC；高并发同一行→TCC（AT 的全局锁会串行化）

 5. **"Seata Server 宕机了怎么办？"**
    - 要点：配置多 TC 实例 + 注册中心（Nacos/ZK/Eureka）；TC 故障时事务会悬挂，需要人工介入或等待超时回滚

 ## 项目实践案例：电商订单系统的分布式事务分层方案

 **场景**：订单系统涉及"订单+库存"（强一致）、"订单+积分"（最终一致）、"订单+通知"（最终一致）三类链路。

 ### 分层治理原则

 **主链路强一致 + 副链路最终一致 + 对账兜底**

 | 场景 | 一致性 | 方案 | 理由 |
 |------|-------|------|------|
 | 订单+库存（下单扣库存） | 强一致 | **Seata AT** | 业务无侵入，快速落地；热点行换 TCC |
 | 订单+支付（支付扣款+入账） | 强一致 | **TCC** | 金融场景锁粒度更细，业务可控 |
 | 订单+积分（下单后加积分） | 最终一致 | **事务消息**（RocketMQ） | 通知类，允许延迟 |
 | 订单+通知（短信/邮件） | 最终一致 | **事务消息** | 非关键路径 |
 | 订单+风控（风险评估） | 最终一致 | **本地消息表** | 异步处理 |
 | 对账兜底 | - | **定时对账任务** | T-1 全表对账 + 抽样实时对账 |

 ### 实际落地代码

 ```java
 // 订单服务（Seata AT 主链路）
 @GlobalTransactional
 public void createOrder(OrderDTO dto) {
     inventoryService.deduct(dto.getSkuId(), dto.getQuantity());  // 库存服务（分支事务）
     orderMapper.insert(dto);                                     // 订单服务（本地事务）
     // 副链路用事务消息，不走 AT
     orderMqProducer.send(new TransactionMessage("order.created", dto));
 }

 // 库存服务（AT 代理 DataSource，无感知）
 @Service
 public class InventoryService {
     public void deduct(String skuId, int quantity) {
         // AT 代理自动拦截 SQL，业务方无需感知
         inventoryMapper.deduct(skuId, quantity);
     }
 }
 ```

 ### 选型决策树

 ```
 是否需要强一致？
 ├─ 是（订单+库存、支付+入账）
 │   ├─ 业务侵入低？→ Seata AT
 │   └─ 业务侵入高（金融）→ TCC
 └─ 否（通知、积分、风控）
     ├─ 业务方运维强？→ 本地消息表
     └─ 想用成熟 MQ？→ 事务消息（RocketMQ）

 无论哪种 → 必须 + 对账兜底（终极保险）
 ```

 ### 工程经验总结

 | 经验 | 说明 |
 |------|------|
 | **分层治理** | 核心链路强一致，副链路最终一致，不搞一刀切 |
 | **对账兜底不能少** | 任何方案都会有边界场景，对账是终极保险 |
 | **AT 是入门首选** | 业务无侵入，快速落地，热点场景再换 TCC |
 | **TCC 适合金融** | 锁粒度更细，业务可控，但业务方要写 Cancel |
 | **事务消息适合通知类** | 允许延迟，用最终一致换性能 |

 ## 速查表（一页扫完）

| 维度 | 内容 |
|------|------|
| **三角色** | TC（Seata Server）+ TM（业务应用）+ RM（代理 DataSource） |
| **一阶段** | 拦截 SQL → 读 before image → 执行 → 读 after image → 同事务写 undo_log → 申请全局锁 → 本地提交 |
| **二阶段成功** | 异步删除 undo_log |
| **二阶段失败** | 读 undo_log → 生成反向 SQL → 本地回滚 |
| **全局锁** | 一阶段释放本地锁但保留全局锁，防止中间态被改 |
| **性能瓶颈** | 全局锁按行加锁，高并发同一行串行化 |
| **vs 2PC** | 一阶段后释放本地锁，不阻塞 |
| **vs TCC** | 低侵入 vs 高侵入；框架自动回滚 vs 业务显式补偿 |

## 关联题目

- ⚠️ 《Seata 的 AT 模式的实现原理》— 2026-09-23 Round 2 Q5, ⭐⭐, 完全没概念，只知"强一致+undo log"
- ⚠️ 《MySQL 的 XA 事务在微服务架构中的挑战 & Seata AT 对 2PC 的关键改进》— 2026-10-10 Round 1 Q9, ⭐⭐, 直接说"不了解 Seata AT"，猜测 AT 是"保持会话"

## 关联知识

- [分布式事务概览与模式分类](./distributed-tx-overview.md)
- [2PC 与 3PC 协议深度解析](./2pc-3pc.md)
- [TCC 与三大坑](./tcc-pitfalls.md)
- [跨境支付方案设计](./cross-border-payment-design.md)

## Anki 候选卡片

**卡片 1**
- Q：Seata AT 模式的三个角色分别是什么？
- A：TC（Transaction Coordinator，Seata Server，协调全局事务）+ TM（Transaction Manager，业务应用代理）+ RM（Resource Manager，代理 DataSource）

**卡片 2**
- Q：AT 模式一阶段的完整流程是什么？
- A：拦截 SQL → 读 before image → 执行业务 SQL → 读 after image → 同本地事务写 undo_log → 向 TC 申请全局锁 → 本地提交

**卡片 3**
- Q：AT 模式的全局锁作用是什么？
- A：防止一阶段提交后、二阶段提交前，其他事务修改同一行数据；一阶段释放本地锁但保留全局锁到二阶段结束

**卡片 4**
- Q：AT 模式和 2PC 的关键区别是什么？
- A：AT 一阶段提交后释放本地锁，不阻塞本地事务；2PC 全程持锁，会阻塞

**卡片 5**
- Q：undo_log 表存什么？
- A：存 before/after image（JSON 格式），回滚时框架读取 undo_log 生成反向 SQL

**卡片 6**
- Q：AT 模式的性能瓶颈是什么？
- A：全局锁按行加锁，高并发同一行会串行化；优化方案：缩短事务、批量提交、换 TCC

**卡片 7**
- Q：AT 模式和 TCC 模式怎么选？
- A：低侵入+快速落地→AT；高可控+可审计→TCC；高并发同一行→TCC（AT 的全局锁会串行化）

**卡片 8**
- Q：Seata AT 模式生产部署需要注意什么？
- A：建 undo_log 表、配 TC 高可用（多实例+注册中心）、监控全局锁占用、设置事务超时、避免 TC 故障导致事务悬挂

**卡片 9**
- Q：XA 在微服务架构下有哪六大工程挑战？
- A：①会话耦合（XA 需事务内保持同一 DB 连接，跨服务不同 DB 实例无法天然延伸）；②长事务阻塞（PREPARE 到 COMMIT 期间所有参与者行锁+连接都被持有）；③协调者阻塞（TC 崩溃在 Prepare 后 Commit 前，2PC 经典问题）；④性能瓶颈（QPS 上不去）；⑤跨库兼容（Oracle/PostgreSQL/SQL Server 的 XA 实现不一致）；⑥扩展性差（RM 数量通常不超过 3-4 个）

**卡片 10**
- Q：Seata AT 相对 2PC 的三大关键改进是什么？
- A：①**两阶段拆分解耦**：2PC 一阶段"加锁不提交"→二阶段"提交/回滚"；AT 一阶段"业务提交+undo_log"→二阶段"清理或补偿"（业务提交后本地锁立即释放）；②**基于日志的自动补偿**：2PC 回滚需 TC 通知 RM 反向操作，AT 直接执行 undo_log 里的反向 SQL；③**全局锁优化锁粒度**：AT 的全局锁是 TC 侧逻辑锁，只在跨全局事务冲突检测时使用

**卡片 11**
- Q：Seata AT 的云原生适配能力有哪些？
- A：①TC 无状态可水平扩展（K8s Operator，多 TC 实例通过 Raft 或共享存储协调）；②RM 无状态可重启（TC 通过事务回查恢复未完成事务）；③支持多种资源（MySQL/Redis/RocketMQ/Kafka）；④业务无侵入（JDBC 代理自动拦截 SQL）；⑤容器化友好（通过 service discovery 找 TC）

**卡片 12**
- Q：AT 模式的四大局限是什么？
- A：①热点行场景全局锁竞争严重（按行加锁，高并发串行化）；②非事务性操作无法覆盖（RPC 调用需 TCC 或事务消息）；③依赖数据库唯一索引（需要合理的主键/索引）；④主要面向 Java 生态（跨语言支持较弱）
