Seata 分布式事務原理
Seata整體機制
兩階段提交協議的演變:
-
一階段:業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。
-
二階段:
- 提交異步化,非常快速地完成。
- 回滾通過一階段的回滾日志進行反向補償。
一階段
過程:
1、解析 SQL:得到 SQL 的類型(UPDATE),表(product),條件(where name = 'TXC')等相關的信息。
2、查詢前鏡像:根據解析得到的條件信息,生成查詢語句,定位數據。
1 select id, name, since from product where name = 'TXC';
得到前鏡像:
id | name | since |
---|---|---|
1 | TXC | 2014 |
3、執行業務 SQL:更新這條記錄的 name 為 'GTS'。
4、查詢后鏡像:根據前鏡像的結果,通過 主鍵 定位數據。
1 select id, name, since from product where id = 1;
得到后鏡像:
id | name | since |
---|---|---|
1 | GTS | 2014 |
5、插入回滾日志:把前后鏡像數據以及業務 SQL 相關的信息組成一條回滾日志記錄,插入到 UNDO_LOG 表中。

1 { 2 "branchId": 641789253, 3 "undoItems": [{ 4 "afterImage": { 5 "rows": [{ 6 "fields": [{ 7 "name": "id", 8 "type": 4, 9 "value": 1 10 }, { 11 "name": "name", 12 "type": 12, 13 "value": "GTS" 14 }, { 15 "name": "since", 16 "type": 12, 17 "value": "2014" 18 }] 19 }], 20 "tableName": "product" 21 }, 22 "beforeImage": { 23 "rows": [{ 24 "fields": [{ 25 "name": "id", 26 "type": 4, 27 "value": 1 28 }, { 29 "name": "name", 30 "type": 12, 31 "value": "TXC" 32 }, { 33 "name": "since", 34 "type": 12, 35 "value": "2014" 36 }] 37 }], 38 "tableName": "product" 39 }, 40 "sqlType": "UPDATE" 41 }], 42 "xid": "xid:xxx" 43 }
6、提交前,向 TC 注冊分支:申請 product 表中,主鍵值等於 1 的記錄的 全局鎖 。
7、本地事務提交:業務數據的更新和前面步驟中生成的 UNDO LOG 一並提交。
8、將本地事務提交的結果上報給 TC。
二階段-回滾
1、收到 TC 的分支回滾請求,開啟一個本地事務,執行如下操作。
2、通過 XID 和 Branch ID 查找到相應的 UNDO LOG 記錄。
3、數據校驗:拿 UNDO LOG 中的后鏡與當前數據進行比較,如果有不同,說明數據被當前全局事務之外的動作做了修改。這種情況,需要根據配置策略來做處理,詳細的說明在另外的文檔中介紹。
4、根據 UNDO LOG 中的前鏡像和業務 SQL 的相關信息生成並執行回滾的語句:
1 update product set name = 'TXC' where id = 1;
5、提交本地事務。並把本地事務的執行結果(即分支事務回滾的結果)上報給 TC。
二階段-提交
1、收到 TC 的分支提交請求,把請求放入一個異步任務的隊列中,馬上返回提交成功的結果給 TC。
2、異步任務階段的分支提交請求將異步和批量地刪除相應 UNDO LOG 記錄。
Seata原理機制驗證
驗證項目使用上一章項目,搭建參考:【SpringCloud】Spring Cloud Alibaba 之 Seata 分布式事務中間件(三十六)
項目中TC、TM、RM關系如下:
一階段-驗證
1、調試啟動項目,在order項目中,遠程調用庫存服務扣減庫存前,增加斷點
2、訪問地址:http://localhost:9011/order/create?userId=1&productId=1&count=10&money=100,創建訂單
3、當程序運行到斷點出,已經運行的創建訂單業務,准備調用庫存服務,查看數據庫(order)中的數據
表order中,有一條數據
表undo_log,有一條數據
其中rollback_info,是一個json,里面內容如下:
beforeImage:表示前鏡像,內容為空表示SQL執行前記錄未創建
afterImage:表示后鏡像,內容為SQL執行后,記錄更新后的值
1 { 2 "@class":"io.seata.rm.datasource.undo.BranchUndoLog", 3 "xid":"192.168.1.4:8091:2013220742", 4 "branchId":2013220749, 5 "sqlUndoLogs":[ 6 "java.util.ArrayList", 7 [ 8 { 9 "@class":"io.seata.rm.datasource.undo.SQLUndoLog", 10 "sqlType":"INSERT", 11 "tableName":"`order`", 12 "beforeImage":{ 13 "@class":"io.seata.rm.datasource.sql.struct.TableRecords$EmptyTableRecords", 14 "tableName":"order", 15 "rows":[ 16 "java.util.ArrayList", 17 [ 18 19 ] 20 ] 21 }, 22 "afterImage":{ 23 "@class":"io.seata.rm.datasource.sql.struct.TableRecords", 24 "tableName":"order", 25 "rows":[ 26 "java.util.ArrayList", 27 [ 28 { 29 "@class":"io.seata.rm.datasource.sql.struct.Row", 30 "fields":[ 31 "java.util.ArrayList", 32 [ 33 { 34 "@class":"io.seata.rm.datasource.sql.struct.Field", 35 "name":"id", 36 "keyType":"PRIMARY_KEY", 37 "type":-5, 38 "value":[ 39 "java.lang.Long", 40 10 41 ] 42 }, 43 { 44 "@class":"io.seata.rm.datasource.sql.struct.Field", 45 "name":"user_id", 46 "keyType":"NULL", 47 "type":-5, 48 "value":[ 49 "java.lang.Long", 50 1 51 ] 52 }, 53 { 54 "@class":"io.seata.rm.datasource.sql.struct.Field", 55 "name":"product_id", 56 "keyType":"NULL", 57 "type":-5, 58 "value":[ 59 "java.lang.Long", 60 1 61 ] 62 }, 63 { 64 "@class":"io.seata.rm.datasource.sql.struct.Field", 65 "name":"count", 66 "keyType":"NULL", 67 "type":4, 68 "value":10 69 }, 70 { 71 "@class":"io.seata.rm.datasource.sql.struct.Field", 72 "name":"money", 73 "keyType":"NULL", 74 "type":3, 75 "value":[ 76 "java.math.BigDecimal", 77 100 78 ] 79 }, 80 { 81 "@class":"io.seata.rm.datasource.sql.struct.Field", 82 "name":"status", 83 "keyType":"NULL", 84 "type":4, 85 "value":0 86 } 87 ] 88 ] 89 } 90 ] 91 ] 92 } 93 } 94 ] 95 ] 96 }
4、查看 seata 庫的
branch_table 表
驗證了向TC注冊了分支
global_table 表
驗證了全局事務ID
lock_table 表
驗證了行鎖
二階段-回滾驗證
1、當業務出錯或超時回滾時,查看 order 庫
order 表 :數據回滾
undo_log 表 :被清空、回滾
2、查看 seata 庫的
branch_table 表:數據回滾、被清空
global_table 表:數據回滾、被清空
lock_table 表:數據回滾、被清空
驗證二階段回滾成功
二階段-提交驗證
1、當業務正常實現,事務提交,查看 order 庫
order 表 :數據改變
undo_log 表 :數據被刪除
2、查看 seata 庫的
branch_table 表:數據被刪除
global_table 表:數據被刪除
lock_table 表:數據被刪除
驗證二階段提交成功