二阶提交协议
全局事务标识 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