MySQL XA事務
MySQL從5.0.3開始支持分佈式事務,當前的分佈式事務只支持InnoDB存儲引擎,在MySQL中,使用分佈式事務的應用程序涉及一個或多個資源管理器和一個事務管理器。
- 資源管理器(Resource Manager):用於提供通向事務資源的途徑,數據庫服務器是一種資源管理器。該資源必須可以提交或回滾由RM管理的事務,例如,多態MySQL數據庫作爲多態資源管理器或者幾臺MySQL和幾臺Oracle作爲資源管理器。
- 事務管理器(Transaction Manager):用於協調作爲一個分佈式事務的一部分的事務,TM與管理每個事務的RMs進行通信。在一個分佈式事務中,各個單個事務均是分佈式事務的“分支事務”。分佈式事務和各分支通過一種命名方法進行標識。
用於執行分佈式事務的過程使用兩階段提交協議,發生時間在由分佈式事務的各個分支需要進行的行動已經執行之後。
- 在第一階段,TM告知所有RM進行prepared操作,即所有RM被告知即將要執行commit操作,通常,這意味着用於管理分支的每個RM會記錄對於被穩定保存的分支的行動,然後分支回答自己是否準備好進行commit操作了。
- 在第二階段,TM告知所有RM進行commit或者回滾。如果在prepare時,有任一各RM回覆說它無法進行commit操作,那麼所有的RM將被告知進行回滾操作,否則所有的RM將被告知進行commit操作。
有些情況下,如果一個分佈式事務只有一個RM,那麼使用一階段提交也可,即該RM會被告知同時進行prepare和commit操作。
XA事務語法
MySQL中與XA事務相關的SQL語句如下:
- XA {START|BEGIN} xid [JOIN|RESUME] #開始一個分佈式事務
- XA END xid [SUSPEND [FOR MIGRATE]]
- XA PREPARE xid # 準備提交事務
- XA COMMIT xid [ONE PHASE] # 提交事務
- XA ROLLBACK xid #回滾事務
- XA RECOVER [CONVERT XID] # 查看處於PREPARE狀態的事務
XID標識一個分佈式事務,其組成:
- xid: gtrid [, bqual [, formatID ]]
- gtrid:必須,爲字符串,表示全局事務標識符
- bqual:可選,爲字符串,默認是空串,表示分支限定符
- formatID:可選,默認值爲1,用於標識由gtrid和bqual值使用的格式
接下來拙劣地演示下這些語句的用法:
有一個user表有兩個分片,分別在3306端口和3307端口的mysql上,灰色會3306上的操作,黑色爲在3307上的操作,現在要從用戶user1轉50給user2:
在兩個節點上分別開啓事務:
進行轉賬操作:
準備提交:
提交:
結果:
XA事務狀態(STATE)
1. 發起XA START後,事務置於ACTIVE STATE
2. 對於一個置於ACTIVE STATE的事務,可以發起多條SQL進行業務操作,然後發起XA END,使事務置於IDLE STATE
3. 對於一個置於IDLE STATE的事務,你可以發起XA PREPARE 或者XA COMMIT ... ONE PHASE語句
- XA PREPARE置事務於PREPARE STATE,告訴MySQL準備提交事務,可以用XA RECOVER語句來查看所有處於PREPARE STATE的事務
- XA COMMIT ... ONE PHASE告訴MySQL準備並提交(兩個操作一起)事務
4. 對於一個置於PREPARE STATE的事務,可以發起XA COMMIT操作提交事務,或者發起XA ROLLBACK操作回滾事務
XA事務與LOCAL事務(LOCAL事務指非分佈式事務,即以start transaction開始,以commit/rollback結束的事務),是互斥的,我們不能在一個LOCAL事務中間開啓一個XA事務:
反之亦然:
問題
之前看到書上說:MySQL的分佈式事務是不完整的。如果分支事務在達到prepare狀態時,數據庫異常重新啓動,重啓後,可以繼續對分支事務進行提交和回滾操作,但是提交的事務不會寫入binlog,會導致:1.使用binlog恢復時丟失部分數據;2.如果存在slave,那麼會導致slave和當前節點數據不一致的現象。我用5.7的MySQL試了一下,發現並不存在這個問題,主從依然能同步,不知道哪個版本開始修復了這個問題