🌺The Begin🌺点点关注,收藏不迷路🌺

引言:从XA到AT的进化

XA模式虽然保证了强一致,但最大的痛点是资源锁定周期过长——从第一阶段开始锁定,直到第二阶段结束才释放,严重影响并发性能。

AT模式同样采用两阶段提交,但巧妙解决了这个问题:第一阶段就提交本地事务释放锁,通过undo-log保证可回滚

AT模式资源锁定

执行后立即提交

一阶段开始

资源已释放

二阶段只需操作undo-log

XA模式资源锁定

锁定资源

释放资源

一阶段开始

二阶段结束

C


一、AT模式核心思想 🎯

1.1 关键创新

AT模式同样是分阶段提交的事务模型,不过却弥补了XA模型中资源锁定周期过长的缺陷。

对比项 XA模式 AT模式
一阶段 执行SQL,不提交,锁定资源 执行SQL,立即提交,释放资源
资源锁定 整个事务期间 仅业务执行期间
回滚依据 数据库undo日志 自定义undo-log表
性能

1.2 核心原理

AT模式通过**记录数据快照(undo-log)**来实现回滚能力,而不是依赖数据库锁:

-- AT模式的核心:undo_log表
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,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

二、完整业务示例:账户余额更新 💰

2.1 初始数据

假设有一个数据库表,记录用户余额:

id money
1 100

其中一个分支业务要执行的SQL为:

UPDATE account SET money = money - 10 WHERE id = 1;

2.2 一阶段执行流程

undo_log表 业务数据库 RM(数据库代理) TC TM undo_log表 业务数据库 RM(数据库代理) TC TM 此时 money = 90,锁已释放! 1. 开启全局事务 返回XID 2. 调用分支事务 3. 查询原始数据 返回 {id:1, money:100} 4. 记录快照(前镜像) 5. 执行业务SQL 更新成功 6. 查询更新后数据 返回 {id:1, money:90} 7. 记录快照(后镜像) 8. 提交本地事务 9. 报告事务状态

一阶段详细步骤

  1. TM发起并注册全局事务到TC
  2. TM调用分支事务
  3. 分支事务准备执行业务SQL
  4. RM拦截业务SQL,根据where条件查询原始数据,形成快照(前镜像)
    前镜像:{"id": 1, "money": 100}
    
  5. RM执行业务SQL,提交本地事务,释放数据库锁
    执行后:money = 90
    
  6. RM记录后镜像并报告状态
    后镜像:{"id": 1, "money": 90}
    

2.3 二阶段执行流程

二阶段

全部成功

有失败

TM通知TC事务结束

TC检查分支状态

通知所有RM删除undo-log

通知所有RM回滚

订单RM删除快照

库存RM删除快照

订单RM读取快照

恢复数据到前镜像

库存RM读取快照

恢复数据到前镜像

场景1:全局提交(所有分支成功)
public class CommitPhase {
    
    // 二阶段提交时RM的工作
    public void commit() {
        // 只需要删除undo-log即可
        undoLogDao.deleteByXidAndBranchId(xid, branchId);
        // 业务数据已经提交,无需额外操作
    }
}
场景2:全局回滚(有分支失败)
public class RollbackPhase {
    
    // 二阶段回滚时RM的工作
    public void rollback() {
        // 1. 读取快照数据
        UndoLog log = undoLogDao.findByXidAndBranchId(xid, branchId);
        
        // 2. 解析前镜像
        // 前镜像:{"id": 1, "money": 100}
        TableRecords beforeImage = log.getBeforeImage();
        
        // 3. 根据前镜像生成回滚SQL
        String rollbackSql = buildRollbackSql(beforeImage);
        // 例如:UPDATE account SET money = 100 WHERE id = 1
        
        // 4. 执行回滚
        jdbcTemplate.execute(rollbackSql);
        
        // 5. 删除已使用的undo-log
        undoLogDao.delete(log);
        
        // 此时数据库再次恢复为100
    }
}

三、AT模式完整时序图 🔄

undo_log2 undo_log1 库存DB 订单DB 库存RM 订单RM TC TM undo_log2 undo_log1 库存DB 订单DB 库存RM 订单RM TC TM alt [所有分支成功] [库存扣减失败] 开启全局事务 XID=123 执行扣款 查询原始数据 余额100 记录前镜像 UPDATE余额=90 记录后镜像 提交事务(释放锁) 注册分支成功 执行扣库存 查询原始库存 库存50 记录前镜像 UPDATE库存=49 记录后镜像 提交事务(释放锁) 注册分支成功 全局提交 删除undo_log 删除undo_log 全局回滚 根据undo_log回滚 读取快照 恢复余额=100 删除日志 根据undo_log回滚 读取快照 恢复库存=50 删除日志

四、AT模式的核心优势 🌟

4.1 资源锁定时间对比

阶段 XA模式 AT模式
业务执行期间 锁定资源 锁定资源
等待二阶段期间 仍锁定资源 资源已释放
总锁定时间 短(仅业务执行期)

4.2 性能对比

public class PerformanceComparison {
    
    // XA模式:锁等待
    // 事务1: UPDATE account SET money=90 WHERE id=1 (锁定中)
    // 事务2: UPDATE account SET money=80 WHERE id=1 (必须等待事务1结束)
    
    // AT模式:无锁等待
    // 事务1: UPDATE account SET money=90 WHERE id=1 (立即提交,释放锁)
    // 事务2: UPDATE account SET money=80 WHERE id=1 (无需等待,直接执行)
    // 如果事务1需要回滚,事务2可能已执行,需要全局回滚
}

五、XA vs AT 模式对比 📊

对比维度 XA模式 AT模式
资源锁定 整个事务期间 仅业务执行期间
一阶段 执行不提交,锁定资源 执行并提交,释放资源
二阶段提交 提交事务 删除undo-log
二阶段回滚 数据库回滚 根据undo-log恢复
性能
一致性 强一致 最终一致
代码侵入

六、总结 🎯

6.1 一句话总结

AT模式通过"业务SQL立即提交释放锁 + undo-log保证可回滚"的创新设计,在保证最终一致性的前提下,大幅提升了分布式事务的性能,是Seata最核心、最常用的模式。

6.2 核心价值

价值 说明
高性能 资源锁定时间短,并发高
无侵入 只需一个@GlobalTransactional注解
可靠 undo-log保证可回滚
通用 适用于大多数业务场景

6.3 选型建议

public class Advice {
    
    public String chooseMode() {
        return "1. 通用业务、高并发场景 → AT模式(首选)\n"
             + "2. 强一致、低并发场景 → XA模式\n"
             + "3. 资源预留、极致性能 → TCC模式";
    }
}

(本文为分布式系统事务系列文章,欢迎关注更多架构深度内容)

在这里插入图片描述


🌺The End🌺点点关注,收藏不迷路🌺
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐