欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

全面解析JTA 深度歷險(xiǎn)

 更新時(shí)間:2017年09月13日 14:59:56   投稿:mengwei  
本文介紹了利用 JTA 深度歷險(xiǎn)的相關(guān)內(nèi)容,充分舉例說明JTA的原理和事務(wù)處理等相關(guān)內(nèi)容,十分詳細(xì),需要的朋友可以參考下。

什么是事務(wù)處理

事務(wù)是計(jì)算機(jī)應(yīng)用中不可或缺的組件模型,它保證了用戶操作的原子性 ( Atomicity )、一致性 ( Consistency )、隔離性 ( Isolation ) 和持久性 ( Durabilily )。關(guān)于事務(wù)最經(jīng)典的示例莫過于信用卡轉(zhuǎn)賬:將用戶 A 賬戶中的 500 元人民幣轉(zhuǎn)移到用戶 B 的賬戶中,其操作流程如下 :

1. 將 A 賬戶中的金額減少 500

2. 將 B 賬戶中的金額增加 500

這兩個(gè)操作必須保正 ACID 的事務(wù)屬性:即要么全部成功,要么全部失?。患偃魶]有事務(wù)保障,用戶的賬號(hào)金額將可能發(fā)生問題:

假如第一步操作成功而第二步失敗,那么用戶 A 賬戶中的金額將就減少 500 元而用戶 B 的賬號(hào)卻沒有任何增加(不翼而飛);同樣如果第一步出錯(cuò) 而第二步成功,那么用戶 A 的賬戶金額不變而用戶 B 的賬號(hào)將增加 500 元(憑空而生)。上述任何一種錯(cuò)誤都會(huì)產(chǎn)生嚴(yán)重的數(shù)據(jù)不一致問題,事務(wù)的缺失對(duì)于一個(gè)穩(wěn)定的生產(chǎn)系統(tǒng)是不可接受的。
J2EE 事務(wù)處理方式

1. 本地事務(wù):緊密依賴于底層資源管理器(例如數(shù)據(jù)庫連接 ),事務(wù)處理局限在當(dāng)前事務(wù)資源內(nèi)。此種事務(wù)處理方式不存在對(duì)應(yīng)用服務(wù)器的依賴,因而部署靈活卻無法支持多數(shù)據(jù)源的分布式事務(wù)。在數(shù)據(jù)庫連接中使用本地事務(wù)示例如下:

清單 1. 本地事務(wù)處理實(shí)例

public void transferAccount() { 
    Connection conn = null; 
    Statement stmt = null; 
    try{ 
      conn = getDataSource().getConnection(); 
      // 將自動(dòng)提交設(shè)置為 false,
      //若設(shè)置為 true 則數(shù)據(jù)庫將會(huì)把每一次數(shù)據(jù)更新認(rèn)定為一個(gè)事務(wù)并自動(dòng)提交
      conn.setAutoCommit(false);
      stmt = conn.createStatement(); 
      // 將 A 賬戶中的金額減少 500 
      stmt.execute("\
      update t_account set amount = amount - 500 where account_id = 'A'");
      // 將 B 賬戶中的金額增加 500 
      stmt.execute("\
      update t_account set amount = amount + 500 where account_id = 'B'");
      // 提交事務(wù)
      conn.commit();
      // 事務(wù)提交:轉(zhuǎn)賬的兩步操作同時(shí)成功
    } catch(SQLException sqle){      
      try{ 
        // 發(fā)生異常,回滾在本事務(wù)中的操做
        conn.rollback();
        // 事務(wù)回滾:轉(zhuǎn)賬的兩步操作完全撤銷
        stmt.close(); 
        conn.close(); 
      }catch(Exception ignore){ 
      } 
      sqle.printStackTrace(); 
    } 
  }

2. 分布式事務(wù)處理 : Java 事務(wù)編程接口(JTA:Java Transaction API)和 Java 事務(wù)服務(wù) (JTS;Java Transaction Service) 為 J2EE 平臺(tái)提供了分布式事務(wù)服務(wù)。分布式事務(wù)(Distributed Transaction)包括事務(wù)管理器(Transaction Manager)和一個(gè)或多個(gè)支持 XA 協(xié)議的資源管理器 ( Resource Manager )。我們可以將資源管理器看做任意類型的持久化數(shù)據(jù)存儲(chǔ);事務(wù)管理器承擔(dān)著所有事務(wù)參與單元的協(xié)調(diào)與控制。JTA 事務(wù)有效的屏蔽了底層事務(wù)資源,使應(yīng)用可以以透明的方式參入到事務(wù)處理中;但是與本地事務(wù)相比,XA 協(xié)議的系統(tǒng)開銷大,在系統(tǒng)開發(fā)過程中應(yīng)慎重考慮是否確實(shí)需要分布式事務(wù)。若確實(shí)需要分布式事務(wù)以協(xié)調(diào)多個(gè)事務(wù)資源,則應(yīng)實(shí)現(xiàn)和配置所支持 XA 協(xié)議的事務(wù)資源,如 JMS、JDBC 數(shù)據(jù)庫連接池等。使用 JTA 處理事務(wù)的示例如下(注意:connA 和 connB 是來自不同數(shù)據(jù)庫的連接)

清單 2. JTA 事務(wù)處理

public void transferAccount() { 
	UserTransaction userTx = null; 
    Connection connA = null; 
    Statement stmtA = null; 
    Connection connB = null; 
    Statement stmtB = null;   
    try{ 
       // 獲得 Transaction 管理對(duì)象
      userTx = (UserTransaction)getContext().lookup("\
         java:comp/UserTransaction"); 
      // 從數(shù)據(jù)庫 A 中取得數(shù)據(jù)庫連接
      connA = getDataSourceA().getConnection();      
      // 從數(shù)據(jù)庫 B 中取得數(shù)據(jù)庫連接
      connB = getDataSourceB().getConnection(); 
            // 啟動(dòng)事務(wù)
      userTx.begin();
      // 將 A 賬戶中的金額減少 500 
      stmtA = connA.createStatement(); 
      stmtA.execute("
      update t_account set amount = amount - 500 where account_id = 'A'");
      // 將 B 賬戶中的金額增加 500 
      stmtB = connB.createStatement(); 
      stmtB.execute("\
      update t_account set amount = amount + 500 where account_id = 'B'");
      // 提交事務(wù)
      userTx.commit();
      // 事務(wù)提交:轉(zhuǎn)賬的兩步操作同時(shí)成功(數(shù)據(jù)庫 A 和數(shù)據(jù)庫 B 中的數(shù)據(jù)被同時(shí)更新)
    } catch(SQLException sqle){ 
      try{ 
         // 發(fā)生異常,回滾在本事務(wù)中的操縱
         userTx.rollback();
        // 事務(wù)回滾:轉(zhuǎn)賬的兩步操作完全撤銷 
        //( 數(shù)據(jù)庫 A 和數(shù)據(jù)庫 B 中的數(shù)據(jù)更新被同時(shí)撤銷)
        stmt.close(); 
        conn.close(); 
        ... 
      }catch(Exception ignore){ 
      } 
      sqle.printStackTrace(); 
    } catch(Exception ne){ 
      e.printStackTrace(); 
    } 
  }

JTA 實(shí)現(xiàn)原理

很多開發(fā)人員都會(huì)對(duì) JTA 的內(nèi)部工作機(jī)制感興趣:我編寫的代碼沒有任何與事務(wù)資源(如數(shù)據(jù)庫連接)互動(dòng)的代碼,但是我的操作(數(shù)據(jù)庫更新)卻實(shí)實(shí)在在的被包含在了事務(wù)中,那 JTA 究竟是通過何種方式來實(shí)現(xiàn)這種透明性的呢? 要理解 JTA 的實(shí)現(xiàn)原理首先需要了解其架構(gòu):它包括事務(wù)管理器(Transaction Manager)和一個(gè)或多個(gè)支持 XA 協(xié)議的資源管理器 ( Resource Manager ) 兩部分, 我們可以將資源管理器看做任意類型的持久化數(shù)據(jù)存儲(chǔ);事務(wù)管理器則承擔(dān)著所有事務(wù)參與單元的協(xié)調(diào)與控制。 根據(jù)所面向?qū)ο蟮牟煌?,我們可以?JTA 的事務(wù)管理器和資源管理器理解為兩個(gè)方面:面向開發(fā)人員的使用接口(事務(wù)管理器)和面向服務(wù)提供商的實(shí)現(xiàn)接口(資源管理器)。其中開發(fā)接口的主要部分即為上述示例中引用的 UserTransaction 對(duì)象,開發(fā)人員通過此接口在信息系統(tǒng)中實(shí)現(xiàn)分布式事務(wù);而實(shí)現(xiàn)接口則用來規(guī)范提供商(如數(shù)據(jù)庫連接提供商)所提供的事務(wù)服務(wù),它約定了事務(wù)的資源管理功能,使得 JTA 可以在異構(gòu)事務(wù)資源之間執(zhí)行協(xié)同溝通。以數(shù)據(jù)庫為例,IBM 公司提供了實(shí)現(xiàn)分布式事務(wù)的數(shù)據(jù)庫驅(qū)動(dòng)程序,Oracle 也提供了實(shí)現(xiàn)分布式事務(wù)的數(shù)據(jù)庫驅(qū)動(dòng)程序, 在同時(shí)使用 DB2 和 Oracle 兩種數(shù)據(jù)庫連接時(shí), JTA 即可以根據(jù)約定的接口協(xié)調(diào)者兩種事務(wù)資源從而實(shí)現(xiàn)分布式事務(wù)。正是基于統(tǒng)一規(guī)范的不同實(shí)現(xiàn)使得 JTA 可以協(xié)調(diào)與控制不同數(shù)據(jù)庫或者 JMS 廠商的事務(wù)資源。

開發(fā)人員使用開發(fā)人員接口,實(shí)現(xiàn)應(yīng)用程序?qū)θ质聞?wù)的支持;各提供商(數(shù)據(jù)庫,JMS 等)依據(jù)提供商接口的規(guī)范提供事務(wù)資源管理功能;事務(wù)管理器( TransactionManager )將應(yīng)用對(duì)分布式事務(wù)的使用映射到實(shí)際的事務(wù)資源并在事務(wù)資源間進(jìn)行協(xié)調(diào)與控制。 下面,本文將對(duì)包括 UserTransaction、Transaction 和 TransactionManager 在內(nèi)的三個(gè)主要接口以及其定義的方法進(jìn)行介紹。

面向開發(fā)人員的接口為 UserTransaction (使用方法如上例所示),開發(fā)人員通常只使用此接口實(shí)現(xiàn) JTA 事務(wù)管理,其定義了如下的方法:

begin()- 開始一個(gè)分布式事務(wù),(在后臺(tái) TransactionManager 會(huì)創(chuàng)建一個(gè) Transaction 事務(wù)對(duì)象并把此對(duì)象通過 ThreadLocale 關(guān)聯(lián)到當(dāng)前線程上 )

commit()- 提交事務(wù)(在后臺(tái) TransactionManager 會(huì)從當(dāng)前線程下取出事務(wù)對(duì)象并把此對(duì)象所代表的事務(wù)提交)

rollback()- 回滾事務(wù)(在后臺(tái) TransactionManager 會(huì)從當(dāng)前線程下取出事務(wù)對(duì)象并把此對(duì)象所代表的事務(wù)回滾)

getStatus()- 返回關(guān)聯(lián)到當(dāng)前線程的分布式事務(wù)的狀態(tài) (Status 對(duì)象里邊定義了所有的事務(wù)狀態(tài),感興趣的讀者可以參考 API 文檔 )

setRollbackOnly()- 標(biāo)識(shí)關(guān)聯(lián)到當(dāng)前線程的分布式事務(wù)將被回滾

面向提供商的實(shí)現(xiàn)接口主要涉及到 TransactionManager 和 Transaction 兩個(gè)對(duì)象

Transaction 代表了一個(gè)物理意義上的事務(wù),在開發(fā)人員調(diào)用 UserTransaction.begin() 方法時(shí) TransactionManager 會(huì)創(chuàng)建一個(gè) Transaction 事務(wù)對(duì)象(標(biāo)志著事務(wù)的開始)并把此對(duì)象通過 ThreadLocale 關(guān)聯(lián)到當(dāng)前線程。UserTransaction 接口中的 commit()、rollback(),getStatus() 等方法都將最終委托給 Transaction 類的對(duì)應(yīng)方法執(zhí)行。Transaction 接口定義了如下的方法:

commit()- 協(xié)調(diào)不同的事務(wù)資源共同完成事務(wù)的提交

rollback()- 協(xié)調(diào)不同的事務(wù)資源共同完成事務(wù)的回滾

setRollbackOnly()- 標(biāo)識(shí)關(guān)聯(lián)到當(dāng)前線程的分布式事務(wù)將被回滾

getStatus()- 返回關(guān)聯(lián)到當(dāng)前線程的分布式事務(wù)的狀態(tài)

enListResource(XAResource xaRes, int flag)- 將事務(wù)資源加入到當(dāng)前的事務(wù)中(在上述示例中,在對(duì)數(shù)據(jù)庫 A 操作時(shí) 其所代表的事務(wù)資源將被關(guān)聯(lián)到當(dāng)前事務(wù)中,同樣,在對(duì)數(shù)據(jù)庫 B 操作時(shí)其所代表的事務(wù)資源也將被關(guān)聯(lián)到當(dāng)前事務(wù)中)
delistResourc(XAResource xaRes, int flag)- 將事務(wù)資源從當(dāng)前事務(wù)中刪除

registerSynchronization(Synchronization sync)- 回調(diào)接口,Hibernate 等 ORM 工具都有自己的事務(wù)控制機(jī)制來保證事務(wù), 但同時(shí)它們還需要一種回調(diào)機(jī)制以便在事務(wù)完成時(shí)得到通知從而觸發(fā)一些處理工作,如清除緩存等。這就涉及到了 Transaction 的回調(diào)接口 registerSynchronization。工具可以通過此接口將回調(diào)程序注入到事務(wù)中,當(dāng)事務(wù)成功提交后,回調(diào)程序?qū)⒈患せ睢?br />

TransactionManager 本身并不承擔(dān)實(shí)際的事務(wù)處理功能,它更多的是充當(dāng)用戶接口和實(shí)現(xiàn)接口之間的橋梁。下面列出了 TransactionManager 中定義的方法,可以看到此接口中的大部分事務(wù)方法與 UserTransaction 和 Transaction 相同。 在開發(fā)人員調(diào)用 UserTransaction.begin() 方法時(shí) TransactionManager 會(huì)創(chuàng)建一個(gè) Transaction 事務(wù)對(duì)象(標(biāo)志著事務(wù)的開始)并把此對(duì)象通過 ThreadLocale 關(guān)聯(lián)到當(dāng)前線程上;同樣 UserTransaction.commit() 會(huì)調(diào)用 TransactionManager.commit(), 方法將從當(dāng)前線程下取出事務(wù)對(duì)象 Transaction 并把此對(duì)象所代表的事務(wù)提交, 即調(diào)用 Transaction.commit()

begin()- 開始事務(wù)

commit()- 提交事務(wù)

rollback()- 回滾事務(wù)

getStatus()- 返回當(dāng)前事務(wù)狀態(tài)

setRollbackOnly()

getTransaction()- 返回關(guān)聯(lián)到當(dāng)前線程的事務(wù)

setTransactionTimeout(int seconds)- 設(shè)置事務(wù)超時(shí)時(shí)間

resume(Transaction tobj)- 繼續(xù)當(dāng)前線程關(guān)聯(lián)的事務(wù)

suspend()- 掛起當(dāng)前線程關(guān)聯(lián)的事務(wù)

在系統(tǒng)開發(fā)過程中會(huì)遇到需要將事務(wù)資源暫時(shí)排除的操作,此時(shí)就需要調(diào)用 suspend() 方法將當(dāng)前的事務(wù)掛起:在此方法后面所做的任何操作將不會(huì)被包括在事務(wù)中,在非事務(wù)性操作完成后調(diào)用 resume()以繼續(xù)事務(wù)(注: 要進(jìn)行此操作需要獲得 TransactionManager 對(duì)象, 其獲得方式在不同的 J2EE 應(yīng)用服務(wù)器上是不一樣的)。

清單 3. 開始事務(wù) - UserTransactionImpl implenments UserTransaction

public void begin() throws NotSupportedException, SystemException { 
  // 將開始事務(wù)的操作委托給 TransactionManagerImpl 
  TransactionManagerImpl.singleton().begin(); 
   }

清單 4. 開始事務(wù) - TransactionManagerImpl implements TransactionManager

// 此處 transactionHolder 用于將 Transaction 所代表的事務(wù)對(duì)象關(guān)聯(lián)到線程上
private static ThreadLocal transactionHolder 
    = new ThreadLocal(); 
   //TransacationMananger 必須維護(hù)一個(gè)全局對(duì)象,因此使用單實(shí)例模式實(shí)現(xiàn)
   private static TransactionManagerImpl singleton = new TransactionManagerImpl(); 
   private TransactionManagerImpl(){  
   } 
   public static TransactionManagerImpl singleton(){ 
    return singleton; 
   } 
   public void begin() throws NotSupportedException, SystemException { 
     //XidImpl 實(shí)現(xiàn)了 Xid 接口,其作用是唯一標(biāo)識(shí)一個(gè)事務(wù)
     XidImpl xid = new XidImpl(); 
     // 創(chuàng)建事務(wù)對(duì)象,并將對(duì)象關(guān)聯(lián)到線程
     TransactionImpl tx = new TransactionImpl(xid); 
     transactionHolder.set(tx); 
   }

現(xiàn)在我們就可以理解 Transaction 接口上沒有定義 begin 方法的原因了:Transaction 對(duì)象本身就代表了一個(gè)事務(wù),在它被創(chuàng)建的時(shí)候就表明事務(wù)已經(jīng)開始,因此也就不需要額外定義 begin() 方法了。

清單 5. 提交事務(wù) - UserTransactionImpl implenments UserTransaction

public void commit() throws RollbackException, HeuristicMixedException, 
    HeuristicRollbackException, SecurityException, 
    IllegalStateException, SystemException { 
    // 檢查是否是 Roll back only 事務(wù),如果是回滾事務(wù)
      if(rollBackOnly){ 
      rollback(); 
      return; 
     } else { 
      // 將提交事務(wù)的操作委托給 TransactionManagerImpl 
      TransactionManagerImpl.singleton().commit(); 
     } 
}

清單 6. 提交事務(wù) - TransactionManagerImpl implenments TransactionManager

public void commit() throws RollbackException, HeuristicMixedException, 
  HeuristicRollbackException, SecurityException, 
  IllegalStateException, SystemException { 
   // 取得當(dāng)前事務(wù)所關(guān)聯(lián)的事務(wù)并通過其 commit 方法提交
   TransactionImpl tx = transactionHolder.get(); 
   tx.commit(); 
       }

同理, rollback、getStatus、setRollbackOnly 等方法也采用了與 commit() 相同的方式實(shí)現(xiàn)。 UserTransaction 對(duì)象不會(huì)對(duì)事務(wù)進(jìn)行任何控制, 所有的事務(wù)方法都是通過 TransactionManager 傳遞到實(shí)際的事務(wù)資源即 Transaction 對(duì)象上。

上述示例演示了 JTA 事務(wù)的處理過程,下面將為您展示事務(wù)資源(數(shù)據(jù)庫連接,JMS)是如何以透明的方式加入到 JTA 事務(wù)中的。首先需要明確的一點(diǎn)是,在 JTA 事務(wù) 代碼中獲得的數(shù)據(jù)庫源 ( DataSource ) 必須是支持分布式事務(wù)的。在如下的代碼示例中,盡管所有的數(shù)據(jù)庫操作都被包含在了 JTA 事務(wù)中,但是因?yàn)?MySql 的數(shù)據(jù)庫連接是通過本地方式獲得的,對(duì) MySql 的任何更新將不會(huì)被自動(dòng)包含在全局事務(wù)中。

清單 7. JTA 事務(wù)處理

public void transferAccount() { 
    UserTransaction userTx = null; 
    Connection mySqlConnection = null; 
    Statement mySqlStat = null; 
    Connection connB = null; 
    Statement stmtB = null; 
    try{ 
        // 獲得 Transaction 管理對(duì)象
      userTx = 
      (UserTransaction)getContext().lookup("java:comp/UserTransaction");
      // 以本地方式獲得 mySql 數(shù)據(jù)庫連接
      mySqlConnection = DriverManager.getConnection("localhost:1111"); 
      // 從數(shù)據(jù)庫 B 中取得數(shù)據(jù)庫連接, getDataSourceB 返回應(yīng)用服務(wù)器的數(shù)據(jù)源
      connB = getDataSourceB().getConnection(); 
            // 啟動(dòng)事務(wù)
      userTx.begin();
      // 將 A 賬戶中的金額減少 500 
      //mySqlConnection 是從本地獲得的數(shù)據(jù)庫連接,不會(huì)被包含在全局事務(wù)中
      mySqlStat = mySqlConnection.createStatement(); 
      mySqlStat.execute("
      update t_account set amount = amount - 500 where account_id = 'A'");
      //connB 是從應(yīng)用服務(wù)器得的數(shù)據(jù)庫連接,會(huì)被包含在全局事務(wù)中
      stmtB = connB.createStatement(); 
      stmtB.execute("
      update t_account set amount = amount + 500 where account_id = 'B'");
      // 事務(wù)提交:connB 的操作被提交,mySqlConnection 的操作不會(huì)被提交
      userTx.commit();
    } catch(SQLException sqle){ 
      // 處理異常代碼
    } catch(Exception ne){ 
      e.printStackTrace(); 
    } 
  }

為什么必須從支持事務(wù)的數(shù)據(jù)源中獲得的數(shù)據(jù)庫連接才支持分布式事務(wù)呢?其實(shí)支持事務(wù)的數(shù)據(jù)源與普通的數(shù)據(jù)源是不同的,它實(shí)現(xiàn)了額外的 XADataSource 接口。我們可以簡(jiǎn)單的將 XADataSource 理解為普通的數(shù)據(jù)源(繼承了 java.sql.PooledConnection),只是它為支持分布式事務(wù)而增加了 getXAResource 方法。另外,由 XADataSource 返回的數(shù)據(jù)庫連接與普通連接也是不同的,此連接除了實(shí)現(xiàn) java.sql.Connection 定義的所有功能之外還實(shí)現(xiàn)了 XAConnection 接口。我們可以把 XAConnection 理解為普通的數(shù)據(jù)庫連接,它支持所有 JDBC 規(guī)范的數(shù)據(jù)庫操作,不同之處在于 XAConnection 增加了對(duì)分布式事務(wù)的支持。

應(yīng)用程序從支持分布式事務(wù)的數(shù)據(jù)源獲得的數(shù)據(jù)庫連接是 XAConnection 接口的實(shí)現(xiàn),而由此數(shù)據(jù)庫連接創(chuàng)建的會(huì)話(Statement)也為了支持分布式事務(wù)而增加了功能,如下代碼所示:

清單 8. JTA 事務(wù)資源處理

public void transferAccount() { 
    UserTransaction userTx = null; 
    Connection conn = null; 
    Statement stmt = null; 
    try{ 
        // 獲得 Transaction 管理對(duì)象
      userTx = (UserTransaction)getContext().lookup("
      java:comp/UserTransaction"); 
      // 從數(shù)據(jù)庫中取得數(shù)據(jù)庫連接, getDataSourceB 返回支持分布式事務(wù)的數(shù)據(jù)源
      conn = getDataSourceB().getConnection(); 
            // 會(huì)話 stmt 已經(jīng)為支持分布式事務(wù)進(jìn)行了功能增強(qiáng)
      stmt = conn.createStatement(); 
            // 啟動(dòng)事務(wù)
      userTx.begin();
      stmt.execute("update t_account ... where account_id = 'A'"); 
      userTx.commit();
    } catch(SQLException sqle){ 
      // 處理異常代碼
    } catch(Exception ne){ 
      e.printStackTrace(); 
    } 
  }

我們來看一下由 XAConnection 數(shù)據(jù)庫連接創(chuàng)建的會(huì)話(Statement)部分的代碼實(shí)現(xiàn)(不同的 JTA 提供商會(huì)有不同的實(shí)現(xiàn)方式,此處代碼示例只是向您演示事務(wù)資源是如何被自動(dòng)加入到事務(wù)中)。 我們以會(huì)話對(duì)象的 execute 方法為例,通過在方法開始部分增加對(duì) associateWithTransactionIfNecessary 方法的調(diào)用,即可以保證在 JTA 事務(wù)期間,對(duì)任何數(shù)據(jù)庫連接的操作都會(huì)被透明的加入到事務(wù)中。

清單 9. 將事務(wù)資源自動(dòng)關(guān)聯(lián)到事務(wù)對(duì)象 - XAStatement implements Statement

public void execute(String sql) { 
        // 對(duì)于每次數(shù)據(jù)庫操作都檢查此會(huì)話所在的數(shù)據(jù)庫連接是否已經(jīng)被加入到事務(wù)中
    associateWithTransactionIfNecessary(); 
    try{ 
           // 處理數(shù)據(jù)庫操作的代碼
       .... 
    } catch(SQLException sqle){ 
      // 處理異常代碼
    } catch(Exception ne){ 
      e.printStackTrace(); 
    } 
  } 
public void associateWithTransactionIfNecessary(){ 
    // 獲得 TransactionManager 
    TransactionManager tm = getTransactionManager(); 
        Transaction tx = tm.getTransaction();
      // 檢查當(dāng)前線程是否有分布式事務(wù)
      if(tx != null){ 
      // 在分布式事務(wù)內(nèi),通過 tx 對(duì)象判斷當(dāng)前數(shù)據(jù)連接是否已經(jīng)被包含在事務(wù)中,
      //如果不是那么將此連接加入到事務(wù)中
      Connection conn = this.getConnection(); 
      //tx.hasCurrentResource, xaConn.getDataSource() 不是標(biāo)準(zhǔn)的 JTA 
            // 接口方法,是為了實(shí)現(xiàn)分布式事務(wù)而增加的自定義方法
      if(!tx.hasCurrentResource(conn)){ 
        XAConnection xaConn = (XAConnection)conn; 
        XADataSource xaSource = xaConn.getDataSource(); 
        // 調(diào)用 Transaction 的接口方法,將數(shù)據(jù)庫事務(wù)資源加入到當(dāng)前事務(wù)中
        tx.enListResource(xaSource.getXAResource(), 1);
        } 
      } 
    }

XAResource 與 Xid: XAResource 是 Distributed Transaction Processing: The XA Specification 標(biāo)準(zhǔn)的 Java 實(shí)現(xiàn),它是對(duì)底層事務(wù)資源的抽象,定義了分布式事務(wù)處理過程中事務(wù)管理器和資源管理器之間的協(xié)議,各事務(wù)資源提供商(如 JDBC 驅(qū)動(dòng),JMS)將提供此接口的實(shí)現(xiàn)。使用此接口,開發(fā)人員可以通過自己的編程實(shí)現(xiàn)分布式事務(wù)處理,但這些通常都是由應(yīng)用服務(wù)器實(shí)現(xiàn)的(服務(wù)器自帶實(shí)現(xiàn)更加高效,穩(wěn)定) 為了說明,我們將舉例說明他的使用方式。

在使用分布式事務(wù)之前,為了區(qū)分事務(wù)使之不發(fā)生混淆,必須實(shí)現(xiàn)一個(gè) Xid 類用來標(biāo)識(shí)事務(wù),可以把 Xid 想象成事務(wù)的一個(gè)標(biāo)志符,每次在新事務(wù)創(chuàng)建是都會(huì)為事務(wù)分配一個(gè) Xid,Xid 包含三個(gè)元素:formatID、gtrid(全局事務(wù)標(biāo)識(shí)符)和 bqual(分支修飾詞標(biāo)識(shí)符)。 formatID 通常是零,這意味著你將使用 OSI CCR(Open Systems Interconnection Commitment, Concurrency 和 Recovery 標(biāo)準(zhǔn))來命名;如果你要使用另外一種格式,那么 formatID 應(yīng)該大于零,-1 值意味著 Xid 為無效。
gtrid 和 bqual 分別包含 64 個(gè)字節(jié)二進(jìn)制碼來分別標(biāo)識(shí)全局事務(wù)和分支事務(wù), 唯一的要求是 gtrid 和 bqual 必須是全局唯一的。

XAResource 接口中主要定義了如下方法:

commit()- 提交事務(wù)

isSameRM(XAResource xares)- 檢查當(dāng)前的 XAResource 與參數(shù)是否同一事務(wù)資源

prepare()- 通知資源管理器準(zhǔn)備事務(wù)的提交工作

rollback()- 通知資源管理器回滾事務(wù)

在事務(wù)被提交時(shí),Transaction 對(duì)象會(huì)收集所有被當(dāng)前事務(wù)包含的 XAResource 資源,然后調(diào)用資源的提交方法,如下代碼所示:

清單 10. 提交事務(wù) - TransactionImpl implements Transaction

public void commit() throws RollbackException, HeuristicMixedException, 
       HeuristicRollbackException, SecurityException, 
       IllegalStateException, SystemException { 
       // 得到當(dāng)前事務(wù)中的所有事務(wù)資源
        List list = getAllEnlistedResouces(); 
       // 通知所有的事務(wù)資源管理器,準(zhǔn)備提交事務(wù)
            // 對(duì)于生產(chǎn)級(jí)別的實(shí)現(xiàn),此處需要進(jìn)行額外處理以處理某些資源準(zhǔn)備過程中出現(xiàn)的異常
       for(XAResource xa : list){ 
         xa.prepare(); 
       } 
       // 所有事務(wù)性資源,提交事務(wù)
       for(XAResource xa : list){ 
         xa.commit(); 
       } 
    }

結(jié)束語

通過如上介紹相信讀者對(duì) JTA 的原理已經(jīng)有所了解,本文中的示例代碼都是理想情況下的假設(shè)實(shí)現(xiàn)。一款完善成熟的 JTA 事務(wù)實(shí)現(xiàn)需要考慮與處理的細(xì)節(jié)非常多,如性能(提交事務(wù)的時(shí)候使用多線程方式并發(fā)提交事務(wù))、容錯(cuò)(網(wǎng)絡(luò),系統(tǒng)異常)等, 其成熟也需要經(jīng)過較長(zhǎng)時(shí)間的積累。感興趣的讀者可以閱讀一些開源 JTA 實(shí)現(xiàn)以進(jìn)一步深入學(xué)習(xí)。希望本文對(duì)大家能有所幫助。

相關(guān)文章

  • java 網(wǎng)絡(luò)編程之TCP通信和簡(jiǎn)單的文件上傳功能實(shí)例

    java 網(wǎng)絡(luò)編程之TCP通信和簡(jiǎn)單的文件上傳功能實(shí)例

    下面小編就為大家分享一篇java 網(wǎng)絡(luò)編程之TCP通信和簡(jiǎn)單的文件上傳功能實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表

    Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表

    這篇文章主要為大家詳細(xì)介紹了Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • java讀取文件顯示進(jìn)度條的實(shí)現(xiàn)方法

    java讀取文件顯示進(jìn)度條的實(shí)現(xiàn)方法

    當(dāng)讀取一個(gè)大文件時(shí),一時(shí)半會(huì)兒無法看到讀取結(jié)果,就需要顯示一個(gè)進(jìn)度條,是程序員明白已經(jīng)讀了多少文件,可以估算讀取還需要多少時(shí)間,下面的代碼可以實(shí)現(xiàn)這個(gè)功能
    2014-01-01
  • Java Stream 流實(shí)現(xiàn)合并操作示例

    Java Stream 流實(shí)現(xiàn)合并操作示例

    這篇文章主要介紹了Java Stream 流實(shí)現(xiàn)合并操作,結(jié)合實(shí)例形式詳細(xì)分析了Java Stream 流實(shí)現(xiàn)合并操作原理與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • AbstractQueuedSynchronizer(AQS)鎖狀態(tài)同步和排隊(duì)管理

    AbstractQueuedSynchronizer(AQS)鎖狀態(tài)同步和排隊(duì)管理

    這篇文章主要介紹了為大家AbstractQueuedSynchronizer(AQS)鎖狀態(tài)同步和排隊(duì)管理源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java實(shí)現(xiàn)動(dòng)態(tài)獲取文件的絕對(duì)路徑

    Java實(shí)現(xiàn)動(dòng)態(tài)獲取文件的絕對(duì)路徑

    我們知道在?Java?中讀取一些配置文件信息,是在開發(fā)中十分常用的要求。這篇文章就來和大家聊聊Java如何實(shí)現(xiàn)動(dòng)態(tài)獲取文件的絕對(duì)路徑,感興趣的可以了解一下
    2023-02-02
  • SpringBoot框架如何管理Xml和CSV

    SpringBoot框架如何管理Xml和CSV

    XML是可擴(kuò)展標(biāo)記語言,是一種用于標(biāo)記電子文件使其具有結(jié)構(gòu)性的標(biāo)記語言。CSV是一種通用的、相對(duì)簡(jiǎn)單的文件格式,通常被用在大數(shù)據(jù)領(lǐng)域,進(jìn)行大規(guī)模的數(shù)據(jù)搬運(yùn)操作,本文將介紹SpringBoot框架如何管理Xml和CSV
    2021-06-06
  • springboot中引入日志文件生成的配置詳解

    springboot中引入日志文件生成的配置詳解

    本文主要介紹了springboot中引入日志文件生成的配置詳解,包括日志級(jí)別的設(shè)置、日志格式的配置以及日志輸出的位置等,從而幫助開發(fā)者更好地進(jìn)行開發(fā)與調(diào)試
    2023-10-10
  • 詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器

    詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器

    本篇文章主要介紹了詳解Spring Boot 定制HTTP消息轉(zhuǎn)換器,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • Java經(jīng)緯度小數(shù)與度分秒相互轉(zhuǎn)換工具類示例詳解

    Java經(jīng)緯度小數(shù)與度分秒相互轉(zhuǎn)換工具類示例詳解

    這篇文章主要介紹了Java經(jīng)緯度小數(shù)與度分秒相互轉(zhuǎn)換工具類,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07

最新評(píng)論