引言:事务世界的"双保险机制"
在分布式系统的星海中,事务管理如同宇宙飞船的导航系统。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模式采用"先尝试后确认"的设计哲学,如同高明的外交家:
- 柔性事务:允许阶段性的中间状态(类似临时停靠空间站)
- 性能优先:通过本地锁代替全局锁(避免太空交通堵塞)
- 最终一致:接受短暂的数据时延(星际通信存在光速限制)
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[全局回滚]