文章目錄
- 前言
- 一、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(): 把這筆事務從系統生命周期中移除(內存 + 數據庫)