XA事務就是兩階段提交的一種實現方式
XA規范主要定義了事務管理器TM,和資源管理器RM之間的接口
根據2PC的規范,將一次事務分割成兩個階段
1. prepare階段
TM向所有RM發送prepare指令,RM接受到指令后執行數據修改和日志記錄等操作,然后返回 可以提交/不可提交 給TM
(按照我的理解應該類似於MySQL在開啟一個事務之后,只差最后的COMMIT或者ROLLBACK的狀態)
2. commit階段
TM接受到所有RM的prepare結果
如果有RM返回是 不可提交 或者超時,那么向所有RM發送ROLLBACK命令
如果所有RM都返回可以提交,那么向所有RM發送COMMIT命令
XA的異常情況處理
MySQL與XA事務的關系有兩種情況
1. 內部XA
在使用innodb作為存儲引擎,並且開啟binlog的情況下,MySQL同時維護了binlog日志與innodb的redo log
為了保證這兩個日志的一致性,MySQL使用了XA事務,由於只在單機上工作,所以被稱為內部XA
2. 外部XA
就是一般談論的分布式事務了
MySQL支持XA START/END/PREPARE/COMMIT這些sql語句,通過使用這些命令,我們是可以完成分布式事務的
狀態轉移圖如下

(我有點不能理解的是,為什么一定需要XA END這個語句,直接XA PREPARE不行嗎)
在MySQL5.7.7之前,XA事務是有bug的
如果有一個XA事務處於PREPARE狀態
1. 如果連接關閉,或者MySQL服務器正常退出,這個事務會被回滾(但是根據XA規范,這個事務應該被保留)
2. 如果MySQL服務器被強制結束,在重啟之后,用XA RECOVER命令可以看到這個事務,這個事務也可以被XA COMMIT所提交,但是相關的binlog記錄會丟失,這樣就會導致數據庫引擎中的數據與binlog中的數據不一致 (參考資料)
這兩個bug被提出了十年之久,終於在5.7.7中被修正了(第一個bug阿里自己也搞了個修正)
就目前來看,MySQL的XA事務現在做得還不錯,應該是可用的
還是有一些不能理解的地方
1. 官方文檔中強調:在使用分布式事務的時候,需要使用串行隔離級別,為什么?
(As with nondistributed transactions, SERIALIZABLE may be preferred if your applications are sensitive to read phenomena. REPEATABLE READ may not be sufficient for distributed transactions.)
原因:為了盡可能提高分布式事物的隔離級別,如果分庫上使用MySQL默認的RR,那么導致總的分布式事務的隔離級別為RU
參考資料
1. MySQL binlog 組提交與 XA(兩階段提交)
2. MySQL redolog與組提交 資料1 資料2 資料3 資料4
3. MySQL官方的XA文檔
4. XA事務的隔離級別
