Seata AT模式下的undo_log流转

📅 发布时间:2026/7/5 21:34:36 👁️ 浏览次数:
Seata AT模式下的undo_log流转
目录表结构字段解读核心机制AT 模式如何工作几个关键点潜在风险点信心评分7/11场景用户下单一、正常流程成功提交1. 订单服务执行 SQL2. 库存服务执行 SQL3. 全局事务提交成功二、回滚流程异常触发时间线TC 发起回滚的完整过程三、回滚逻辑总结四、完整流程图表结构字段解读字段类型作用idBIGINT PK自增主键branch_idBIGINT分支事务 IDSeata 为每个参与者分配的唯一标识xidVARCHAR(100)全局事务 ID格式通常是xid:port:threadidcontextVARCHAR(128)上下文信息Seata 内部使用如序列化器类型rollback_infoLONGBLOB核心字段— 存储回滚数据前后镜像的序列化 bloblog_statusINT日志状态0已提交正常完成1已回滚log_createdDATETIME创建时间log_modifiedDATETIME最后修改时间extVARCHAR扩展字段核心机制AT 模式如何工作1. 执行前 → 生成前镜像before image ─┐ 2. 执行业务SQL │ 写入 undo_log 3. 执行后 → 生成后镜像after image ─┘ 4. 提交本地事务连同 undo_log 一起提交 5. 如果全局回滚 → 根据 undo_log 中的镜像数据执行反向补偿回滚逻辑示例-- 原 SQL: UPDATE account SET balance 100 WHERE id 1 -- 前镜像: SELECT balance FROM account WHERE id 1 → 得到 200 -- 后镜像: SELECT balance FROM account WHERE id 1 → 得到 100 ​ -- 回滚时: -- 1. 校验后镜像防止脏写确认当前值还是 100 -- 2. 用前镜像恢复: UPDATE account SET balance 200 WHERE id 1几个关键点1. 为什么用 LONGBLOBrollback_info存的是完整的行级变更数据前后镜像一行数据可能很大如果批量操作如INSERT INTO ... SELECT单条 undo_log 可能包含成百上千行的前后镜像2. 为什么需要唯一索引ux_undo_logxid branch_id唯一 → 保证一个分支事务在同一个表里只有一条 undo_log 记录防止重复插入和重复回滚3. 正常情况下的行为事务提交成功 → Seata TC 通知 RM 删除对应的 undo_log异步清理所以正常情况下这张表应该基本是空的如果表里积压了大量数据说明 TC-RM 之间通信有问题或者清理任务没跑4. 清理策略默认保留 7 天可通过seata.server.undo.logDeletePeriod配置Seata Server 有定时任务异步删除已处理的 undo_log潜在风险点问题原因应对undo_log 堆积TC 清理任务未执行 / 网络不通检查 Seata Server 和 Nacos 连通性表空间暴涨大批量操作如百万行 UPDATE考虑分批执行或切换 TCC 模式脏写检测失败前后镜像与实际数据不一致检查是否有绕过 Seata 的直接 SQL 操作回滚失败undo_log 数据丢失或损坏检查事务隔离级别和日志保留配置信心评分7/11对表结构和 AT 模式原理有把握但ext字段的具体用途和某些配置参数的默认值我不完全确定暂无来源可查。需要我深入分析某个具体方面吗比如如何监控这张表的健康状态或者 AT 模式 vs TCC 模式的选择场景用户下单涉及两个服务订单服务INSERT INTO order ...库存服务UPDATE stock SET quantity quantity - 1 WHERE sku_id 1001两个服务都注册了 Seata AT 模式走全局事务。一、正常流程成功提交1. 订单服务执行 SQL-- 业务 SQL INSERT INTO order(user_id, product_id, quantity) VALUES (1, 1001, 1);Seata AT 模式自动执行-- ① 前镜像因为是 INSERT没有前镜像Seata 记录 null -- ② 执行业务 SQL INSERT INTO order(user_id, product_id, quantity) VALUES (1, 1001, 1); -- ③ 后镜像 SELECT * FROM order WHERE id 1; -- 查出刚插入的那行undo_log 表中写入一条记录字段值id1branch_id2001001001xid192.168.1.102:8091:1234567890contextserizalizerjacksonrollback_info(二进制 blob见下方 JSON 还原)log_status0log_created2026-06-29 11:00:00log_modified2026-06-29 11:00:00rollback_info 内容JSON 还原{ sqlType: INSERT, tableImage: { tableName: order, afterImage: [ { id: 1, user_id: 1, product_id: 1001, quantity: 1 } ], beforeImage: null } }2. 库存服务执行 SQL-- 业务 SQL UPDATE stock SET quantity quantity - 1 WHERE sku_id 1001;Seata AT 模式自动执行-- ① 前镜像 SELECT quantity FROM stock WHERE sku_id 1001; -- 得到 100 -- ② 执行业务 SQL UPDATE stock SET quantity quantity - 1 WHERE sku_id 1001; -- ③ 后镜像 SELECT quantity FROM stock WHERE sku_id 1001; -- 得到 99undo_log 表中写入一条记录字段值id2branch_id2001001002xid192.168.1.102:8091:1234567890contextserizalizerjacksonrollback_info(二进制 blob见下方 JSON 还原)log_status0log_created2026-06-29 11:00:01log_modified2026-06-29 11:00:01rollback_info 内容JSON 还原{ sqlType: UPDATE, tableImage: { tableName: stock, beforeImage: [ { sku_id: 1001, quantity: 100 } ], afterImage: [ { sku_id: 1001, quantity: 99 } ] } }3. 全局事务提交成功TCSeata Server→ 通知所有 RM 提交成功 → 各 RM 异步删除对应的 undo_log → undo_log 表变回空的二、回滚流程异常触发假设库存扣减后订单服务报错了比如数据库超时。时间线11:00:00 订单服务 → undo_log 写入 ✓ → 订单本地提交 ✓ 11:00:01 库存服务 → undo_log 写入 ✓ → 库存本地提交 ✓ 11:00:02 订单服务代码异常 → TM 向 TC 发起全局回滚TC 发起回滚的完整过程TC 向库存服务的 RM 发送回滚指令TC → RM(stock): 请回滚 branch_id2001001002库存服务 RM 收到指令后执行-- Step 1: 查出 undo_log SELECT rollback_info FROM undo_log WHERE branch_id 2001001002 AND xid 192.168.1.102:8091:1234567890; -- 得到 rollback_info: -- { -- sqlType: UPDATE, -- beforeImage: [{sku_id: 1001, quantity: 100}], -- afterImage: [{sku_id: 1001, quantity: 99}] -- } -- Step 2: 校验防止脏写 -- 检查当前 quantity 是否还 afterImage 中的 99 SELECT quantity FROM stock WHERE sku_id 1001; -- 如果当前值 ≠ 99 → 说明有其他事务干扰 → 抛异常需要人工介入 -- 如果当前值 99 → 继续回滚 -- Step 3: 用前镜像恢复 UPDATE stock SET quantity 100 WHERE sku_id 1001; -- 补偿完成 -- Step 4: 删除 undo_log标记为已回滚 DELETE FROM undo_log WHERE branch_id 2001001002;TC 向订单服务的 RM 发送回滚指令TC → RM(order): 请回滚 branch_id2001001001订单服务 RM 收到指令后执行-- Step 1: 查出 undo_log SELECT rollback_info FROM undo_log WHERE branch_id 2001001001; -- 得到 rollback_info: -- { -- sqlType: INSERT, -- beforeImage: null, -- afterImage: [{id: 1, user_id: 1, product_id: 1001, quantity: 1}] -- } -- Step 2: INSERT 的回滚 删除 DELETE FROM order WHERE id 1; -- Step 3: 删除 undo_log DELETE FROM undo_log WHERE branch_id 2001001001;三、回滚逻辑总结SQL 类型回滚操作原理INSERTDELETE把插入的行删掉DELETEINSERT用前镜像把删掉的行插回去UPDATEUPDATE用前镜像把值恢复回去四、完整流程图正常流程 业务SQL → Seata代理 → 前镜像 → 执行SQL → 后镜像 → undo_log入库 → 本地提交 → TC确认 → 删除undo_log 回滚流程 异常发生 → TM通知TC → TC通知RM → 查undo_log → 校验防脏写→ 用前镜像反向补偿 → 删除undo_log核心思想undo_log 就是一张后悔药表记录了每个数据变更的前后状态出问题时能精确恢复到原始值。