Seata服务端回滚事务核心源码解析
文章目录
- 前言
- 一、doGlobalRollback
- 3.1、changeGlobalStatus
- 3.2、doGlobalRollback
前言
本篇介绍Seata服务端接收到客户端TM回滚请求,进行处理并且驱动所有的RM进行回滚的源码。
一、doGlobalRollback
doGlobalRollback
是全局回滚的方法:
首先依旧是进行校验,添加监听器。然后会关闭会话,阻止新分支注册,保证了在回滚执行期间,不会再有分支悄悄进来。:
- 判断事务是否还在「初始状态」,如果是,就可以把状态改为 Rollbacking。
- 否则说明这个事务已经处于回滚中或提交中,可能是别的线程已经发起操作;就不再做重复回滚处理。
- 在
doGlobalRollback
中完成全局事务回滚的逻辑。
3.1、changeGlobalStatus
该方法主要是用于修改表中的状态:
- 将
lock_table
表中对应XID的状态改为回滚。 - 将
global_table
表中对应XID的状态改为回滚。
3.2、doGlobalRollback
doGlobalRollback
的逻辑和提交事务的逻辑类似,也是有几个关键部分:
- 得到当前XID下的所有分支事务。
- 遍历这些分支事务。
- 拿到分支事务的状态,如果状态是一阶段提交失败,就直接移除该分支,然后继续下次循环。
- 驱动RM回滚。
- 根据RM返回的错误码判断。
- 执行最后的清理工作。
根据RM返回的错误码:
PhaseTwo_Rollbacked
代表回滚成功,会执行removeBranch
的逻辑,删除该分支在lock_table
,branch_table
以及branchSessions
中的记录。PhaseTwo_RollbackFailed_Unretryable
代表回滚失败,并且无法重试了,会执行endRollbackFailed
的逻辑。
endRollbacked
方法中,根据不同的状态,对global_table
的状态进行修改。
最终都会执行globalSession.end();
方法,清除全局事务在lock_table
表中的记录,然后清理掉global_table
的记录。
那既然 globalSession.end() 最终会物理删除 global_table 的记录,那为什么前面还要调用 globalSession.changeGlobalStatus(…) 去更新状态?
changeGlobalStatus() 虽然最终会更新数据库中的 status 字段,但是在过程中它触发了事务生命周期钩子机制,供系统其他部分观察状态变化。
changeGlobalStatus(): 我告诉所有人,这个事务已经结束了(并以某种状态结束)
end(): 把这笔事务从系统生命周期中移除(内存 + 数据库)