MySQL 中基於 XA 實現的分散式事務
https://blog.csdn.net/zhailuxu/article/details/80948926
首先我們來簡要看下分散式事務處理的XA規範
可知XA規範中分散式事務有AP,RM,TM組成:
其中應用程式(Application Program ,簡稱AP):AP定義事務邊界(定義事務開始和結束)並訪問事務邊界內的資源。
資源管理器(Resource Manager,簡稱RM):Rm管理計算機共享的資源,許多軟體都可以去訪問這些資源,資源包含比如資料庫、檔案系統、印表機伺服器等。
事務管理器(Transaction Manager ,簡稱TM):負責管理全域性事務,分配事務唯一標識,監控事務的執行進度,並負責事務的提交、回滾、失敗恢復等。
Xa主要規定了RM與TM之間的互動,下面來看下XA規範中定義的RM 和 TM互動的介面:
本圖來著 參考文章XA規範25頁
xa_start負責開啟或者恢復一個事務分支,並且管理XID到呼叫執行緒
xa_end 負責取消當前執行緒與事務分支的關聯
xa_prepare負責詢問RM 是否準備好了提交事務分支
xa_commit通知RM提交事務分支
xa_rollback 通知RM回滾事務分支
XA協議是使用了二階段協議的,其中:
第一階段TM要求所有的RM準備提交對應的事務分支,詢問RM是否有能力保證成功的提交事務分支,RM根據自己的情況,如果判斷自己進行的工作可以被提交,那就就對工作內容進行持久化,並給TM回執OK;否者給TM的回執NO。RM在傳送了否定答覆並回滾了已經的工作後,就可以丟棄這個事務分支資訊了。
第二階段TM根據階段1各個RM prepare的結果,決定是提交還是回滾事務。如果所有的RM都prepare成功,那麼TM通知所有的RM進行提交;如果有RM prepare回執NO的話,則TM通知所有RM回滾自己的事務分支。
也就是TM與RM之間是通過兩階段提交協議進行互動的。
5.2 MySQL中XA實現
MYSQL的資料庫儲存引擎InnoDB的事務特效能夠保證在儲存引擎級別實現ACID,而分散式事務讓儲存引擎級別的事務擴充套件到資料庫層面,甚至擴充套件到多個資料庫之間,這是通過兩階段提交協議來實現的,MySQL 5.0或者更新版本開始支援XA事務,從下圖可知MySQL中只有InnoDB引擎支援XA協議:
Mysql中存在兩種XA事務,一種是內部XA事務主要用來協調儲存引擎和二進位制日誌,一種是外部事務可以參與到外部分散式事務中(比如多個資料庫實現的分散式事務),本節我們主要討論外部事務。
在MySQL資料庫分散式事務中,MySQL是XA事務過程中的資源管理器(RM)存在的,TM是連線MySQL伺服器的客戶端。MySQL資料庫是作為RM存在的,在分散式事務中一般會涉及到至少兩個RM,所以我們說的MySQL支援XA協議是說mysql作為RM來說的,也就是說MySQL實現了XA協議中RM應該具有的功能;需要注意的是MySQL中只有當隔離級別為Serializable時候才能使用分散式事務,所以需要使用set global tx_isolation='serializable',session tx_isolation='serializable';設定資料庫隔離級別(具體可以參考本地事務)。
下面我們來看看在MySQL資料庫單個節點執行XA事務,首先來看下MySQL下xa事務語法:
其中xid是一個全域性唯一的id標示一個分支事務,每個分支事務有自己的全域性唯一的一個id,是一個字串。
然後確認下mysql是否啟動了xa功能:
可知啟動了,下面具體看一個例項:
其中首先使用XA START ‘xid’ 啟動了一個XA事務,並把它置於ACTIVE狀態
對於一個ACTIVE狀態的 XA事務,我們可以執行構成事務的多條SQL語句,也就是指定分支事務的邊界,然後執行一個XA END ‘xid’語句,XA END把事務放入IDLE狀態,也就是結束事務邊界,在xa start和xa end之間的語句就構成了本分支事務的一個事務範圍。當呼叫xa end ‘xid1’後由於結束了事務邊界,所以這時候如何在執行sql語句會丟擲ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state錯誤,也就是當分支事務處於IDLE狀態時候不允許執行沒有包含到分支事務邊界裡面的其他sql.
對於一個IDLE 狀態XA事務,可以執行一個XA PREPARE語句或一個XA COMMIT…ONE PHASE語句,其中XA PREPARE把事務放入PREPARED狀態。在此點上的XA RECOVER語句將在其輸出中包括事務的xid值,因為XA RECOVER會列出處於PREPARED狀態的所有XA事務。XA COMMIT…ONE PHASE用於預備和提交事務,也就是轉換為一階段協議,直接提交事務。
對於一個PREPARED狀態的 XA事務,可以執行XA COMMIT 語句來提交或者執行XA ROLLBACK來回滾xa事務。
其中二階段協議中第一階段是執行 xa prepare時候,這時候MySQL客戶端(TM)向MySQL資料庫伺服器(RM)發出prepare”準備提交”請求,資料庫收到請求後執行資料修改和日誌記錄等處理,處理完成後只是把事務的狀態改成”可以提交”,然後把結果返回給事務管理器。
如果第一階段中資料庫都prepare成功,那麼mysql客戶端(TM)向資料庫伺服器發出”commit”請求,資料庫伺服器把事務的”可以提交”狀態改為”提交完成”狀態,然後返回應答。如果在第一階段內資料庫的操作發生了錯誤,或者mysql客戶端(RM)收不到資料庫的回應,則認為事務失敗,執行rollback回撤所有資料庫的事務。
上面例子是在一個資料庫節點上執行的一個分支事務,演示了單個資料庫上執行xa分支事務的流程,但是通常都是使用程式語言,比如Java的 JTA來完成MySQL的分散式事務的,下面一個例子用來演示:
首先新增依賴
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
程式碼:
public class XaDemo {
public static MysqlXADataSource getDataSource(String connStr, String user, String pwd) {
try {
MysqlXADataSource ds = new MysqlXADataSource();
ds.setUrl(connStr);
ds.setUser(user);
ds.setPassword(pwd);
return ds;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] arg) {
String connStr1 = "jdbc:mysql://192.168.0.1:3306/test";
String connStr2 = "jdbc:mysql://192.168.0.2:3306/test";
try {
//從不同資料庫獲取資料庫資料來源
MysqlXADataSource ds1 = getDataSource(connStr1, "root", "123456");
MysqlXADataSource ds2 = getDataSource(connStr2, "root", "123456");
//資料庫1獲取連線
XAConnection xaConnection1 = ds1.getXAConnection();
XAResource xaResource1 = xaConnection1.getXAResource();
Connection connection1 = xaConnection1.getConnection();
Statement statement1 = connection1.createStatement();
//資料庫2獲取連線
XAConnection xaConnection2 = ds2.getXAConnection();
XAResource xaResource2 = xaConnection2.getXAResource();
Connection connection2 = xaConnection2.getConnection();
Statement statement2 = connection2.createStatement();
//建立事務分支的xid
Xid xid1 = new MysqlXid(new byte[] { 0x01 }, new byte[] { 0x02 }, 100);
Xid xid2 = new MysqlXid(new byte[] { 0x011 }, new byte[] { 0x012 }, 100);
try {
//事務分支1關聯分支事務sql語句
xaResource1.start(xid1, XAResource.TMNOFLAGS);
int update1Result = statement1.executeUpdate("update account_from set money=money - 50 where id=1");
xaResource1.end(xid1, XAResource.TMSUCCESS);
//事務分支2關聯分支事務sql語句
xaResource2.start(xid2, XAResource.TMNOFLAGS);
int update2Result = statement2.executeUpdate("update account_to set money= money + 50 where id=1");
xaResource2.end(xid2, XAResource.TMSUCCESS);
// 兩階段提交協議第一階段
int ret1 = xaResource1.prepare(xid1);
int ret2 = xaResource2.prepare(xid2);
// 兩階段提交協議第二階段
if (XAResource.XA_OK == ret1 && XAResource.XA_OK == ret2) {
xaResource1.commit(xid1, false);
xaResource2.commit(xid2, false);
System.out.println("reslut1:" + update1Result + ", result2:" + update2Result);
}
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
如上程式碼對兩個機器上的資料庫進行轉賬操作。
相關文章
- XA式、非XA式Spring分散式事務的實現Spring分散式
- 關於XA分散式事務(weblogic中的XA概念)分散式Web
- MySQL資料庫分散式事務XA的實現原理分析MySql資料庫分散式
- 基於RocketMQ實現分散式事務MQ分散式
- Spring分散式事務XA事務(兩段提交2PC)實現Spring分散式
- ## 【分散式事務】面試官問我:MySQL中的XA事務崩潰瞭如何恢復??分散式面試MySql
- 基於Seata探尋分散式事務的實現方案分散式
- php基於dtm分散式事務管理器實現tcc模式分散式事務demoPHP分散式模式
- Spring的分散式事務實現(JTA+XA/2PC)Spring分散式
- Laravel基於reset機制實現分散式事務Laravel分散式
- 實戰與原理:如何基於RocketMQ實現分散式事務?MQ分散式
- MassTransit | 基於StateMachine實現Saga編排式分散式事務Mac分散式
- 分散式事務(3)---RocketMQ實現分散式事務原理分散式MQ
- Spring Cloud Seata系列:基於AT模式實現分散式事務SpringCloud模式分散式
- 基於可靠訊息方案的分散式事務(二):Java中的事務分散式Java
- 深度剖析分散式事務之 AT 與 XA 對比分散式
- 分散式事務(4)---RocketMQ實現分散式事務專案分散式MQ
- 構建基於RocketMQ的分散式事務服務MQ分散式
- 基於微服務框架Micronaut和Eventuate Tram實現分散式事務的開源案例微服務框架分散式
- 分散式事務:基於可靠訊息服務分散式
- MassTransit 知多少 | 基於MassTransit Courier實現Saga 編排式分散式事務分散式
- 基於RocketMq的分散式事務解決方案MQ分散式
- GRIT:eBay基於微服務的分散式事務協議微服務分散式協議
- 如何實現跨Mysql、Redis和Mongo分散式事務? - dongfuMySqlRedisGo分散式
- 分散式事務的幾種實現方式分散式
- 使用JOTM實現分散式事務的例子分散式
- [譯] Spring 的分散式事務實現-使用和不使用XA — 第三部分Spring分散式
- [譯] Spring 的分散式事務實現 — 使用和不使用 XA — 第二部分Spring分散式
- Dapr實現一個簡單的基於.net分散式事務之Saga模式分散式模式
- 微服務痛點-基於Dubbo + Seata的分散式事務(AT)模式微服務分散式模式
- 分散式事務(一)—分散式事務的概念分散式
- 分散式事務(八)Spring Cloud微服務系統基於Rocketmq可靠訊息最終一致性實現分散式事務分散式SpringCloud微服務MQ
- 關於分散式事務的理解分散式
- [譯] Spring 的分散式事務實現 — 使用和不使用 XA — 第一部分Spring分散式
- 資料庫分散式事務的實現原理!資料庫分散式
- 基於 Zookeeper 的分散式鎖實現分散式
- 基於redis的分散式鎖實現Redis分散式
- 跨Mysql、Redis、Mongo的分散式事務MySqlRedisGo分散式