中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于 XA 事務協議,用代碼實現一個二階段分布式事務

發布時間:2020-08-18 05:55:24 來源:ITPUB博客 閱讀:225 作者:千鋒Python唐小強 欄目:編程語言

在具體的 Demo 之前,先來補充一點 XA 事務的知識: DTP 模型與 XA 規范

DTP 模型與 XA 規范是由 X/Open 維護,也就是現在的 open group,官方網址:http://www.opengroup.org/。open group 是一個獨立的組織,主要負責制定各種行業技術標準。由各大知名公司或者廠商進行支持,主要有如下公司:

基于 XA 事務協議,用代碼實現一個二階段分布式事務

open group 目前有八家公司,華為就是其中的一家。在分布式事務處理(Distributed Transaction Processing,簡稱DTP)方面,X/Open主要提供了以下參考文檔:

  • DTP 參考模型: https://pubs.opengroup.org/onlinepubs/9294999599/toc.pdf
  • DTP XA規范: https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf

DTP 模型

在《Distributed Transaction Processing: Reference Model 》 第3版中,規定了構成 DTP 模型的 5個基本元素:

  • 應用程序(Application Program ,簡稱AP):用于定義事務邊界(即定義事務的開始和結束),并且在事務邊界內對資源進行操作,可以簡單理解為我們的應用程序。
  • 資源管理器(Resource Manager,簡稱RM):如數據庫、文件系統等,并提供訪問資源的方式。
  • 事務管理器(Transaction Manager ,簡稱TM):負責分配事務唯一標識,監控事務的執行進度,并負責事務的提交、回滾等。
  • 通信資源管理器(Communication Resource Manager,簡稱CRM):控制一個TM域(TM domain)內或者跨TM域的分布式應用之間的通信。
  • 通信協議(Communication Protocol,簡稱CP):提供CRM提供的分布式應用節點之間的底層通信服務。

DTP 模型元素更深層次的東西可以參考 opengroup 的文檔,接下來聊一聊 DTP 實例,一個 DTP 實例至少包含  AP、RMs、TM 三部分。如下圖所示:

基于 XA 事務協議,用代碼實現一個二階段分布式事務

我們可以看出 AP、RMs、TM 三者之間都是有交互的,大概流程如下:

  • AP 從 RMs 中獲取數據庫資源,個人認為可以簡單的理解成一條數據庫鏈接,就像我們常用的數據連接一樣。
  • TM 事務資源管理器,負責分配事務唯一標識,監控事務的執行進程,并負責事務的提交、回滾等。AP 會將自己的事務綁定到 TM 中,剩下的事情就交給 TM了。
  • TM 根據收集的結果告訴 RMs(具體的數據庫,例如 MySQL ) 是執行回滾還是提交。

那什么是 XA 協議呢?XA 規范是定義交互接口,從上面的圖中可以看出,整個 DTP 中,有三個交互接口,XA 規范主要是 TM 和 RMs 之間。下面這張圖好理解一些:

基于 XA 事務協議,用代碼實現一個二階段分布式事務

好了,關于 DTP 模型與 XA 規范就聊這么多,具體的可以查看 opengroup 提供的文檔,下面就用我們熟悉的 MySQL 數據庫來實現一個 XA 事務協議第二階段提交。

MySQL 從5.0.3開始支持XA分布式事務,且只有InnoDB存儲引擎支持。如下圖:

基于 XA 事務協議,用代碼實現一個二階段分布式事務

其他的我就不說了,這里我提一下 XA 事務狀態,一個完整的事務流程如下:

  • 1.使用 XA START 來啟動一個 XA 事務,并把它置于 ACTIVE 狀態。
  • 2.對于一個 ACTIVE 狀態的 XA 事務,我們可以執行構成事務的 SQL 語句,然后發布一個 XA END 語句。XA END 把事務放入 IDLE狀態。
  • 3.對于一個IDLE 狀態XA事務,可以執行一個 XA PREPARE 語句或一個XA COMMIT…ONE PHASE 語句:XA PREPARE 把事務放入 PREPARED 狀態。在此點上的 XA RECOVER 語句將在其輸出中包括事務的 xid 值,因為 XA RECOVER 會列出處于 PREPARED 狀態的所有 XA 事務。XA COMMIT…ONE PHASE 用于預備和提交事務。xid 值將不會被 XA RECOVER 列出,因為事務終止。
  • 對于一個 PREPARED 狀態的 XA事務,您可以發布一個 XA COMMIT 語句來提交和終止事務,或者發布XA ROLLBACK來回滾并終止事務。

總結一下,XA 事務, 通過 Start 啟動一個 XA 事務,并且被置為 Active 狀態,處在 active 狀態的事務可以執行 SQL 語句,通過 END 方法將 XA 事務置為 IDLE 狀態。處于 IDLE 狀態可以執行 PREPARE 操作或者 COMMIT…ONE PHASE 操作,也就是二階段提交中的第一階段,PREPARED 狀態的 XA事務的時候就可以 Commit 或者 RollBack,也就是二階段提交的第二階段

可能你注意到了上面有一個 XID 值,簡單的講一下,MySQL 中使用xid來作為一個事務分支的標識符。關于 xid 在 XA 規范中有定義,XA規范定義了一個xid由4個部分組成:

  • gtrid:全局事務標識符(global transaction identifier),最大不能超過64字節。
  • bqual:分支限定符(branch qualifier),最大不能超過64字節。
  • data:xid的值,其是 gtrid和bqual拼接后的內容。
  • formatId:formatId的作用就是記錄gtrid、bqual的格式,類似于memcached中flags字段的作用。

好了,關于 XA 事務就 BB 這么多了,接下來,我們通過一個實例,來實現一把基于 XA 事務協議第二階段提交。

場景: 模擬現金 + 紅包組合支付,假設我們購買了 100 塊錢的東西,90塊使用現金支付,10 塊紅包支付,現金和紅包處在不同的庫。

假設: 現在有兩個庫:xa_account(賬戶庫,現金庫)、xa_red_account(紅包庫)。兩個庫下面都有一張 account 表,account 表中的字段也比較簡單,就 id、user_id、balance_amount 三個字段,SQL 我就不貼了。

好了,具體代碼如下:

public class XaDemo {

   public static void main(String[] args) throws Exception{
       
       // 是否開啟日志
       boolean logXaCommands = true;

       // 獲取賬戶庫的 rm(ap做的事情)
       Connection accountConn = DriverManager.getConnection("jdbc:mysql://106.12.12.xxxx:3306/xa_account?useUnicode=true&characterEncoding=utf8","root","xxxxx");
       XAConnection accConn = new MysqlXAConnection((JdbcConnection) accountConn, logXaCommands);
       XAResource accountRm = accConn.getXAResource();
       // 獲取紅包庫的RM
       Connection redConn = DriverManager.getConnection("jdbc:mysql://106.12.12.xxxx:3306/xa_red_account?useUnicode=true&characterEncoding=utf8","root","xxxxxx");
       XAConnection Conn2 = new MysqlXAConnection((JdbcConnection) redConn, logXaCommands);
       XAResource redRm = Conn2.getXAResource();
// XA 事務開始了
       // 全局事務
       byte[] globalId = UUID.randomUUID().toString().getBytes();
       // 就一個標識
       int formatId = 1;

       // 賬戶的分支事務
       byte[] accBqual = UUID.randomUUID().toString().getBytes();;
       Xid xid = new MysqlXid(globalId, accBqual, formatId);

       // 紅包分支事務
       byte[] redBqual = UUID.randomUUID().toString().getBytes();;
       Xid xid1 = new MysqlXid(globalId, redBqual, formatId);
       try {
           // 賬號事務開始 此時狀態:ACTIVE
           accountRm.start(xid, XAResource.TMNOFLAGS);
           // 模擬業務
           String sql = "update account set balance_amount=balance_amount-90 where user_id=1";
           PreparedStatement ps1 = accountConn.prepareStatement(sql);
           ps1.execute();
           accountRm.end(xid, XAResource.TMSUCCESS);
// 賬號 XA 事務 此時狀態:IDLE
           // 紅包分支事務開始
           redRm.start(xid1, XAResource.TMNOFLAGS);
           // 模擬業務
           String sql1 = "update account set balance_amount=balance_amount-10 where user_id=1";
           PreparedStatement ps2 = redConn.prepareStatement(sql1);
           ps2.execute();
           redRm.end(xid1, XAResource.TMSUCCESS);            // 第一階段:準備提交
           int rm1_prepare = accountRm.prepare(xid);
           int rm2_prepare = redRm.prepare(xid1);

//  XA 事務 此時狀態:PREPARED  
           // 第二階段:TM 根據第一階段的情況決定是提交還是回滾
           boolean //TM判斷有2個事務分支,所以不能優化為一階段提交
           if (rm1_prepare == XAResource.XA_OK && rm2_prepare == XAResource.XA_OK) {
               accountRm.commit(xid, onePhase);
               redRm.commit(xid1, onePhase);
           } else {
               accountRm.rollback(xid);
               redRm.rollback(xid1);
           }

       } catch (Exception e) {
           // 出現異常,回滾
           accountRm.rollback(xid);
           redRm.rollback(xid1);
           e.printStackTrace();
       }
   }
}

運行程序,可以看到如下結果:

基于 XA 事務協議,用代碼實現一個二階段分布式事務

從圖中可以清楚看出 XA 事務兩階段提交過程,更多細節請查閱 MySQL 數據庫 XA Transactions 模塊。

今天的分享就這些,希望這篇文章對你的學習或者工作有所幫助.

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

普定县| 新营市| 长丰县| 阳春市| 库伦旗| 万宁市| 左云县| 田东县| 广西| 灌云县| 屯昌县| 南丹县| 日喀则市| 营口市| 呼玛县| 当阳市| 安阳市| 揭西县| 临桂县| 南部县| 营山县| 邹平县| 青阳县| 汝南县| 东阳市| 安泽县| 商都县| 阿克陶县| 西乌| 鲁山县| 嘉荫县| 拉萨市| 团风县| 金昌市| 兴宁市| 肃南| 固始县| 滨海县| 湄潭县| 苏尼特左旗| 佛冈县|