最近阅读seata代码时,发现的一种出现脏数据情况,做个记录 (默认为AT模式)
1.出现问题的流程
已知在默认情况下,分支事务提交之前会向TC申请全局锁,随后等待TM -> TC 发起全局事务提交或者回滚,TC在处理全局事务提交的时候,需要做如下几件事情
1. 删除全局事务所有对应的分支事务占用的全局锁
2. 将全局事务状态状态改变由 Begin -> AsyncCommitting
3. 异步定时任务通知分支事务删除undoLog
由于步骤1,2,3并不是原子的,所以存在上述时序图中①与②出现一种情况就是,TC删除了全局锁,但是此时TC发生重启or宕机的情况
那么此时,出现了新的全局事务,就可以去修改当前全局事务本应该rollback的数据
2.用一个例子来说明这种情况
- 以下假设分支事务执行了以下Update操作将此份undoLog保存到数据库中
- SQL 为 update product set name = ‘GTS’ where name = ‘TXC’;
{
"branchId": 641789253,
"undoItems": [{
"afterImage": {
"rows": [{
"fields": [{
"name": "id",
"type": 4,
"value": 1
}, {
"name": "name",
"type": 12,
"value": "GTS"
}, {
"name": "since",
"type": 12,
"value": "2014"
}]
}],
"tableName": "product"
},
"beforeImage": {
"rows": [{
"fields": [{
"name": "id",
"type": 4,
"value": 1
}, {
"name": "name",
"type": 12,
"value": "TXC"
}, {
"name": "since",
"type": 12,
"value": "2014"
}]
}],
"tableName": "product"
},
"sqlType": "UPDATE"
}],
"xid": "xid:xxx"
}
- 回滚发生错误时的流程
如果这种情况发生,那么后续这个新的全局事务提交的话,就发生了脏数据的情况