Seata服务端同步提交事务核心源码解析
文章目录
- 前言
- 一、doGlobalCommit(同步提交)
- 2.1、closeAndClean()
- 2.2、changeGlobalStatus
- 2.3、doGlobalCommit
- 2.3.1、findGlobalSession
- 总结
前言
本篇介绍Seata服务端TC如何驱动RM提交事务。
一、doGlobalCommit(同步提交)
doGlobalCommit
是提交事务的方法:
首先会根据客户端传递的XID,查找是否存在全局事务,如果不存在,就直接返回客户端Finished
,同样地,如果超时,直接返回给客户端TimeoutRollbacking
。
添加一个监听器,然后利用SessionManager
执行lambda表达式中的逻辑:
- 如果全局事务的状态非Begin,直接返回false。
- 如果全局事务的状态Begin
- 关闭事务,释放全局锁
- 驱动所有的RM提交事务,还要考虑到支持异步提交的场景。
2.1、closeAndClean()
closeAndClean
的作用是释放全局锁,如果是AT模式,还需要执行clean
的方法:
选择数据库的实现
最终会释放锁 删除lock_table
的记录:
根据客户端发送的XID删除,最终会执行如下的SQL:
delete from lock_table where xid = ? ;
2.2、changeGlobalStatus
同步提交的情况下:
最终会走到DataBaseTransactionStoreManager
的writeSession
的update
分支:
**执行如下的sql,更新global_table 的状态为2 **
update global_table set status = ?,gmt_modified = now() where xid = ?;
commit在同步提交的情况下,会走到doGlobalCommit
分支:
2.3、doGlobalCommit
在doGlobalCommit
方法中,首先会判断,如果当前的模式是SAGA,则走SAGA的这一部分逻辑。否则就是其他模式的提交
首先会执行globalSession.getSortedBranches()
方法,获取所有的分支事务信息:
转换了一下源码中的写法,更加清晰易懂一点。
2.3.1、findGlobalSession
最终会调用到DataBaseTransactionStoreManager
的readSession
:
底层实际上是执行了两条SQL:
-- 查询的是global_table 表中所有的字段,简化成了*
select * from global_table where xid = ?";
-- 查询分支事务表,查出某个主线事务下的所有分支事务
select * from branch_table where xid = 上一条sql查询结果中的xid(主线事务的XID) order by gmt_create asc
最终将当前主线事务下的分支事务,加到branchSessions
集合中:
在最外层SessionHelper#forEach
中,会去遍历所有的分支事务,
得到当前XID下的所有分支事务后,遍历所有的分支事务,执行lambda表达式中的内容:
如果分支在第一阶段就失败了,说明这个分支没有成功参与事务,因此可以将其从全局事务中移除,并继续下一个。PhaseOne_Failed
的状态,是TC 已记录了这个分支(即注册成功),但分支主动上报自己第一阶段失败的结果,如果是因为RM业务发生了异常,则Spring 事务机制自动回滚,Seata 也不会写 undo log,也不会向 TC 汇报任何分支
在branchCommit
方法中,TC会驱动每一个RM去提交事务,然后根据RM返回的状态去判断。
- 如果返回的是
PhaseTwo_Committed
两阶段提交成功,则执行removeBranch
,主要是删除该分支在lock_table
的记录,并且删除branch_table
的记录,清理branchSessions
- 如果返回的是
PhaseTwo_CommitFailed_Unretryable
两阶段提交失败并且无法重试,则将整个全局事务标记为提交失败(Finished + 状态为 CommitFailed),并将其从内存事务会话中清理掉。
最后会进行全局事务的最终处理,删除全局事务信息。
总结
Seata 服务端在同步提交全局事务的过程中,主要完成了以下工作:
- 释放锁,删除
lock_table
的记录。 - 将
global_table
表中的状态改为2。 - 遍历并驱动所有的分支事务提交(Phase Two 提交),每个分支由 TC 向对应的 RM 发起提交请求。
- 根据各分支事务返回的状态进行处理:
- 若分支返回
PhaseTwo_Committed
,表示该分支已成功提交,TC 会调用removeBranch
方法:清理内存中的branchSession
,并删除该分支在branch_table
和lock_table
中的记录。 - 若分支返回
PhaseTwo_CommitFailed_Unretryable
,表示分支提交失败且不可重试,TC 会将全局事务状态设置为CommitFailed
(属于结束状态),并清理内存中的全局事务会话。
- 若分支返回
- 所有分支提交完成后,TC 会将
global_table
中该全局事务的状态更新为Committed
(提交成功)或CommitFailed
(提交失败)。 - 如果全局事务已完成且所有资源已释放,TC 会清理
global_table
中对应事务的记录,以完成整个分布式事务的生命周期管理。