菜单
本页目录

二阶提交协议

全局事务标识 Xid Xid 是全局事务的唯一标识符,由事务协调者(TC)生成,贯穿整个分布式事务生命周期。 Xid 通过事务传播机制(如 HTTP Header 或 RPC 上下文)在微服务链路中传递,确保所有分支事务(Branch Transaction)归属同一全局事务。

一阶段(Phase 1) 分支事务提交 前镜像(Before Image):执行 SQL 前的数据快照,用于回滚时恢复原始数据。 后镜像(After Image):执行 SQL 后的数据快照,用于提交时验证数据一致性(防脏写)。 Undo Log:分支事务在提交前会将前镜像、后镜像和业务 SQL 信息写入 undo_log 表,与本地事务一起提交(保证原子性)。 关键点:undo_log 的写入与业务 SQL 在同一个本地事务中完成,确保事务失败时自动回滚。 全局锁机制 锁申请:在一阶段,资源管理器(RM)执行业务 SQL 前会向 TC 申请全局锁(目标记录的 RowKey)。 锁冲突:若其他全局事务已持有锁,当前事务会回滚本地操作并重试,避免并发修改导致数据不一致(实现隔离性)。 锁释放:全局锁在二阶段完成后释放(提交或回滚)。

二阶段(Phase 2) 提交(Commit) 异步删除 Undo Log:TC 通知所有分支事务提交,RM 异步删除对应的 undo_log 记录(无需数据修改,只需清理日志)。 释放全局锁:提交完成后释放全局锁。 回滚(Rollback) 反向补偿:TC 通知分支事务回滚,RM 根据 undo_log 中的前镜像生成反向 SQL(如 UPDATE 还原数据、DELETE 回插数据)。 数据校验:执行反向 SQL 前,校验当前数据与后镜像是否一致,若不一致说明存在脏写,触发异常处理流程。 删除 Undo Log:回滚完成后删除 undo_log 记录并释放锁。 分支事务提交时会将前镜像和后镜像都存到undo_log表中方便回滚 同时进行事务时,会申请一个锁,获得锁的才能对数据进行操作,可以避免高并发同时修改数据的问题

概括如下

通过打断点的形式可以查看二阶提交的数据库内容 undo_log的回滚信息如下,储存了前镜像和后镜像内容

{
  "@class": "org.apache.seata.rm.datasource.undo.BranchUndoLog",
  "xid": "192.168.200.1:8091:6260609896044851214",
  "branchId": 6260609896044851215,
  "sqlUndoLogs": [
    "java.util.ArrayList",
    [
      {
        "@class": "org.apache.seata.rm.datasource.undo.SQLUndoLog",
        "sqlType": "UPDATE",
        "tableName": "storage_tbl",
        "beforeImage": {
          "@class": "org.apache.seata.rm.datasource.sql.struct.TableRecords",
          "tableName": "storage_tbl",
          "rows": [
            "java.util.ArrayList",
            [
              {
                "@class": "org.apache.seata.rm.datasource.sql.struct.Row",
                "fields": [
                  "java.util.ArrayList",
                  [
                    {
                      "@class": "org.apache.seata.rm.datasource.sql.struct.Field",
                      "name": "count",
                      "keyType": "NULL",
                      "type": 4,
                      "value": 100
                    },
                    {
                      "@class": "org.apache.seata.rm.datasource.sql.struct.Field",
                      "name": "id",
                      "keyType": "PRIMARY_KEY",
                      "type": 4,
                      "value": 1
                    }
                  ]
                ]
              }
            ]
          ]
        },
        "afterImage": {
          "@class": "org.apache.seata.rm.datasource.sql.struct.TableRecords",
          "tableName": "storage_tbl",
          "rows": [
            "java.util.ArrayList",
            [
              {
                "@class": "org.apache.seata.rm.datasource.sql.struct.Row",
                "fields": [
                  "java.util.ArrayList",
                  [
                    {
                      "@class": "org.apache.seata.rm.datasource.sql.struct.Field",
                      "name": "count",
                      "keyType": "NULL",
                      "type": 4,
                      "value": 98
                    },
                    {
                      "@class": "org.apache.seata.rm.datasource.sql.struct.Field",
                      "name": "id",
                      "keyType": "PRIMARY_KEY",
                      "type": 4,
                      "value": 1
                    }
                  ]
                ]
              }
            ]
          ]
        }
      }
    ]
  ]
}

事务模式

Seata默认使用AT模式

可以在配置文件中切换

seata:
  data-source-proxy-mode: XA