[SeataAT-1]AT模式基本原理——工程流程/事务日志表/事务日志管理器

91 阅读3分钟

引言:事务世界的"双保险机制"

在分布式系统的星海中,事务管理如同宇宙飞船的导航系统。AT模式(Auto Transaction)就像一位精明的时光旅者,通过"事前快照+事后补偿"的双保险机制,在业务代码的星辰大海中自由穿梭。让我们通过三个维度,揭开它的神秘面纱。


一、工作流程示例:快递配送的启示

1.1 场景隐喻

想象你在电商平台下单(全局事务),系统需要完成三个操作:扣库存(A服务)、创建订单(B服务)、增加积分(C服务)。这就像快递员需要依次经过三个中转站才能完成配送。

1.2 两阶段流程

阶段一(发货准备)

// GlobalTransactionScanner 自动代理业务方法
@GlobalTransactional
public void purchase(String userId, String commodityCode, int count) {
    stockService.deduct(commodityCode, count); // 扣库存
    orderService.create(userId, commodityCode, count); // 创建订单
    creditService.add(userId, count); // 增加积分
}

每个服务执行时,Seata就像贴心的快递员,在发货前先拍下快照(before image),记录包裹的原始状态。

阶段二(最终确认)

// DefaultCore.java
public void commit() {
    for (ResourceManager rm : resourceManagers.values()) {
        rm.commit(branchId, xid); // 向所有RM发送提交指令
    }
}

当所有中转站确认可以接收包裹(资源锁定),系统才会正式发货(提交事务)。若某个中转站爆仓(服务异常),则启动逆向物流(回滚)。


二、事务日志表:分布式系统的"记忆水晶"

2.1 表结构解析

每个服务的数据库中都藏着名为undo_log的记忆水晶:

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,      -- 分支事务ID
  `xid` varchar(100) NOT NULL,          -- 全局事务ID  
  `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`)
);

2.2 快照生成原理

当执行UPDATE操作时:

// AbstractDMLBaseExecutor.executeAutoCommitTrue
protected T executeAutoCommitTrue(Object[] args) throws Throwable {
    // 1. 拍摄修改前快照
    TableRecords beforeImage = beforeImage();
    
    // 2. 执行DML操作
    T result = statementCallback.execute(...);
    
    // 3. 拍摄修改后快照
    TableRecords afterImage = afterImage(beforeImage);
    
    // 4. 保存记忆水晶
    UndoLogManager.insertUndoLog(...);
}

这个过程就像用双摄像头同时拍摄商品包装前后的对比照片,确保退换货时有据可依。


三、事务日志管理器:时空管理局

3.1 核心职责

事务日志管理器如同《星际穿越》中的五维空间管理员,主要职能包括:

  • 时空坐标管理(XID生成)
  • 平行宇宙快照存储(undo_log存取)
  • 时间线修复(事务补偿)

3.2 源码探秘

事务提交

// DefaultTransactionManager.commit
public void commit(String xid) {
    // 1. 检查所有分支状态
    GlobalSession session = GlobalSession.getSession(xid);
    
    // 2. 异步批量提交(星际舰队集体跃迁)
    session.getBranchSessions().parallelStream().forEach(branch -> {
        RmRpcClient.getInstance().sendMsg(branch.getResourceId(), 
            BranchCommitRequest.build(branch));
    });
    
    // 3. 清理记忆水晶
    UndoLogManager.deleteUndoLog(xid, branchId);
}

事务回滚

// AbstractUndoExecutor.undo
public void undo() {
    // 1. 读取记忆水晶
    Connection conn = DataSourceUtils.getConnection(dataSourceProxy);
    UndoLog log = UndoLogManager.selectUndoLog(conn, xid, branchId);
    
    // 2. 构建逆向SQL(时光倒流)
    String rollbackSQL = buildRollbackSQL(log.getRollbackInfo());
    
    // 3. 执行补偿操作
    StatementCallback.executeUpdate(conn, rollbackSQL);
    
    // 4. 删除已使用的快照
    UndoLogManager.deleteUndoLog(xid, branchId);
}

这就像当某个星际快递出现异常时,系统能根据快照精确回退到事务开始前的状态。


四、设计哲学:优雅的妥协艺术

AT模式采用"先尝试后确认"的设计哲学,如同高明的外交家:

  1. 柔性事务:允许阶段性的中间状态(类似临时停靠空间站)
  2. 性能优先:通过本地锁代替全局锁(避免太空交通堵塞)
  3. 最终一致:接受短暂的数据时延(星际通信存在光速限制)
graph TD
    A[业务方法开始] --> B{是否全局事务?}
    B -->|是| C[注册分支事务]
    C --> D[生成before image]
    D --> E[执行业务SQL]
    E --> F[生成after image]
    F --> G[写入undo_log]
    G --> H{是否所有分支就绪?}
    H -->|是| I[全局提交]
    H -->|否| J[全局回滚]