<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    鷹翔宇空

    學(xué)習(xí)和生活

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      110 Posts :: 141 Stories :: 315 Comments :: 1 Trackbacks
    下文引自:http://mywelt.net/?q=node/2046

    Uwe Weber
    Informix 和 DB2 UDB 的 IT 專家, IBM Germany

    簡介
    在現(xiàn)代企業(yè)環(huán)境中,用多個(gè)數(shù)據(jù)庫和多種品牌的數(shù)據(jù)庫來存儲(chǔ)公司數(shù)據(jù)已經(jīng)不足為奇。最終,這些數(shù)據(jù)將會(huì)在不同數(shù)據(jù)庫外進(jìn)行比較、合并。

    如果您有一個(gè)異構(gòu)的數(shù)據(jù)庫環(huán)境,并且計(jì)劃將不同數(shù)據(jù)庫中的數(shù)據(jù)收集到一個(gè)單獨(dú)的應(yīng)用程序中,那么您就應(yīng)該可以使用傳統(tǒng)技術(shù)執(zhí)行該任務(wù)。在使用 Java 時(shí),您將通過 JDBC 處理所有的數(shù)據(jù)庫操作。清單 1 展示了在 Java 應(yīng)用程序中如何連接 DB2 UDB 和 IDS 的代碼片斷。

    清單 1. 使用 JDBC 建立到不同數(shù)據(jù)庫的連接
    
      1 try { // load JDBC drivers
      2     Class.forName (JDBC_DRIVER_DB2);
      3     Class.forName (JDBC_DRIVER_IDS);
      4 }
      5 catch (Exception e) {
      6     // error handling
      7 }
      8
      9 try { // establish connection and proceed with operation
     10     con_db2 = DriverManager.getConnection (DBURL_DB2);
     11     con_ids = Drivermanager.getConnection (DBURL_IDS);
     12
     13     Statement stmt_db2 = con_db2.createStatement ();
     14     Statement stmt_ids = con_ids.createStatement ();
     15
     16     ResultSet rs_db2 = stmt_db2.executeQuery (SQL);
     17     ResultSet rs_ids = stmt_ids.executeQuery (SQL);
     18
     19     // do something very important with the result sets...
     20 }
     21 catch (SQLException e) {
     22     // error handling
     23 }
    

    兩階段提交協(xié)議簡介
    清單 1 中的演示允許您修改不同數(shù)據(jù)庫中的數(shù)據(jù)。代替執(zhí)行查詢,它可以使用 JDBC 方法 executeUpdate() 執(zhí)行數(shù)據(jù)修改。

    但是如果您需要在單個(gè)事務(wù)中封裝到 DB2 和 IDS 表的新一行的 insert,要做什么呢?
    意思就是說,如果其中一條 insert 語句失敗了,就應(yīng)該將數(shù)據(jù)庫(這里:兩種數(shù)據(jù)庫?。┑某跏紶顟B(tài)恢復(fù)為客戶機(jī)未執(zhí)行任何動(dòng)作的狀態(tài)。該行為可以通過使用兩階段提交(Two-Phase-Commit)協(xié)議完成。這一標(biāo)準(zhǔn)化協(xié)議描述了如何實(shí)現(xiàn)分布式事務(wù)(XA)分布式工作單元(Distributed Unit of Work,DUOW)的技術(shù),以達(dá)到跨數(shù)據(jù)庫系統(tǒng)的一致狀態(tài)(根據(jù) ACID)。

    常規(guī)事務(wù)(單階段提交)中,由 COMMITROLLBACK 所執(zhí)行的事務(wù)終止是一種決定性的操作,與之相反,兩階段提交(Two-Phase-Commit)事務(wù)是分為兩步(階段)進(jìn)行的。

    首先,兩階段提交(Two-Phase-Commit)事務(wù)的啟動(dòng)與常規(guī)的單階段提交(One-Phase-Commit)事務(wù)類似。接著,應(yīng)用程序/客戶機(jī)對該兩階段提交(Two-Phase-Commit)操作中所涉及的所有數(shù)據(jù)庫執(zhí)行其修改工作。現(xiàn)在,在最終提交該事務(wù)之前,客戶機(jī)通知參與的數(shù)據(jù)庫準(zhǔn)備提交(第 1 階段)。如果客戶機(jī)從數(shù)據(jù)庫收到一條“okay”,就發(fā)出命令向數(shù)據(jù)庫提交該事務(wù)(第 2 階段)。最后分布式事務(wù)(Distributed Transaction)結(jié)束。

    兩階段提交(Two-Phase-Commit)中的第 1 階段十分重要。通過首先詢問數(shù)據(jù)庫是否可以進(jìn)行提交,一旦某一參與的數(shù)據(jù)庫報(bào)告錯(cuò)誤,就有機(jī)會(huì)立即中止整個(gè)事務(wù)。因而,第 2 階段將由 ROLLBACK,而非 COMMIT 完成。

    圖 1 提供了對于兩階段提交(Two-Phase-Commit)協(xié)議如何工作的圖形化印象。正如所演示的,分布式事務(wù)(Distributed Transaction)使用由元組表示的描述符(例如:[x,b1])。其意思是,一個(gè)分布式事務(wù)(Distributed Transaction)包含兩個(gè)元素。首先,有一個(gè)惟一全局事務(wù) ID(global transaction id) —— 代表分布式事務(wù)(Distributed Transaction)的簡單標(biāo)識(shí)符 - 由 x 表示,第二個(gè)是分支 ID(branch id),它描述整個(gè)事務(wù)的一部分。一般,分支指的是一個(gè)數(shù)據(jù)庫連接。如果您有一個(gè)將處理兩個(gè)參與數(shù)據(jù)庫的分布式事務(wù)(Distributed Transaction),您就可以用諸如 [100,1] 的描述符表示一個(gè)數(shù)據(jù)庫,用諸如 [100,2] 的描述符表示另一數(shù)據(jù)庫。因此本例中,就有一個(gè)編號(hào)為 100 的全局事務(wù),其中包含兩個(gè) ID 分別為 1 和 2 的分支。

    “但是”,您或許會(huì)問,“如果在兩階段提交(Two-Phase-Commit)協(xié)議的第 2 階段中出現(xiàn)錯(cuò)誤,又將發(fā)生什么事情呢?”
    “的確,您將陷入麻煩中!”
    實(shí)際上,稍后我們將會(huì)討論該主題。

    圖 1. 兩階段提交中的時(shí)間線和應(yīng)用程序流

    請看 清單 2。在第 16-19 行代碼中,您可能錯(cuò)覺地認(rèn)為第 17 和 18 行的語句都是屬于由 con_db2.setAutoCommit(false)(第 16 行)所定義的事務(wù)邊界的一部分。而事實(shí)卻是該行代碼啟動(dòng)了一個(gè)顯式事務(wù),用于連接到由 con_db2.commit()(第 19 行)所提交的 DB2 數(shù)據(jù)庫。第 18 行中所做的修改不受該事務(wù)的影響。本例沒有使用兩階段提交(Two-Phase-Commit)協(xié)議,因此,它不是一個(gè)分布式事務(wù)(Distributed Transaction)。無論是到 DB2 數(shù)據(jù)庫的連接,還是到 Informix Dynamic Server(IDS)的連接,它們都沒有意識(shí)到彼此的存在。

    清單 2. 非“兩階段提交”的應(yīng)用程序
    
      1 try {
      2     Class.forName (JDBC_DRIVER_DB2);
      3     Class.forName (JDBC_DRIVER_IDS);
      4 }
      5 catch (Exception e) {
      6     // error handling
      7 }
      8
      9 try {
     10     con_db2 = DriverManager.getConnection (DBURL_DB2);
     11     con_ids = Drivermanager.getConnection (DBURL_IDS);
     12
     13     Statement stmt_db2 = con_db2.createStatement ();
     14     Statement stmt_ids = con_ids.createStatement ();
     15   
     16     con_db2.setAutoCommit (false);
     17     stmt_db2.executeUpdate (SQL);
     18     stmt_ids.executeUpdate (SQL);
     19     con_db2.commit ();
     20   
     21     // further processing
     22 }
     23 catch (SQLException e) {
     24    // error handling
     25 }
    

    JTA 和事務(wù)管理器(TM)
    Java Transaction API 允許您操作應(yīng)用程序中的分布式事務(wù)(Distributed Transaction)。JTA 中有一組方法,它將傳統(tǒng)的 JDBC 調(diào)用封裝到了兩階段提交(Two-Phase-Commit)協(xié)議中。

    在異構(gòu)環(huán)境中,您通常會(huì)發(fā)現(xiàn)一個(gè)事務(wù)管理器(Transaction Manager),負(fù)責(zé)處理分布式事務(wù)。(實(shí)際上,事務(wù)管理器可以完成大量的工作負(fù)載平衡。)因此,不僅存在到數(shù)據(jù)庫的直接連接,還有到事務(wù)管理器(Transaction Manager)的連接。這就是 JTA 發(fā)揮作用的地方:JTA 是 Java 應(yīng)用程序和事務(wù)管理器(Transaction Manager)之間的接口。圖 2 演示了一個(gè)包含分布式事務(wù)的典型環(huán)境。

    由于存在事務(wù)管理器(Transaction Manager),它通常包含在應(yīng)用程序服務(wù)器(Application Server)中,就不再有兩層(Two-Tier)架構(gòu)。傳統(tǒng)的客戶/服務(wù)器(Client/Server)架構(gòu)已經(jīng)由三層(Tree-Tier)架構(gòu)所取代,三層架構(gòu)包含應(yīng)用程序/客戶機(jī)、事務(wù)管理器(Transaction Manager)/應(yīng)用程序服務(wù)器(Application Server)數(shù)據(jù)庫服務(wù)器,而數(shù)據(jù)庫服務(wù)器一般稱作 XA Resource

    圖 2. 三層架構(gòu)

    1. 包含 SQL 和 JTA 調(diào)用的 Java 應(yīng)用程序。
    2. 管理分布式事務(wù)的應(yīng)用程序服務(wù)器(Application Server)。
    3. 參與分布式事務(wù)的數(shù)據(jù)庫。
    4. Java 應(yīng)用程序向應(yīng)用程序服務(wù)器(Application Server)提交常規(guī) SQL 語句和通用的 XA 調(diào)用。
    5. 應(yīng)用程序所發(fā)送的消息由應(yīng)用程序服務(wù)器(Application Server)進(jìn)行處理,并使用 SQL 和數(shù)據(jù)庫供應(yīng)商特定的 XA 調(diào)用發(fā)送給數(shù)據(jù)庫。

    通常,應(yīng)用程序服務(wù)器(Application Server)提供了應(yīng)用程序可以使用的多種服務(wù)。在談到分布式事務(wù)時(shí),該服務(wù)就稱作 XA Resource。當(dāng)然,在應(yīng)用程序可以使用 XA Resource 之前,首先要在應(yīng)用程序服務(wù)器中注冊和配置 XA Resource。

    現(xiàn)在,如果您計(jì)劃在應(yīng)用程序中使用 JTA,就必須修改代碼,以便還可以與應(yīng)用程序服務(wù)器(Application Server)進(jìn)行通信。這包括一些附加的方法調(diào)用和指定的錯(cuò)誤/異常處理。請參閱 清單 3,以了解如何工作。

    用 JTA 進(jìn)行兩階段提交的必要條件
    首先,在編寫 JTA 應(yīng)用程序時(shí),您需要合適的 JDK。好消息就是在使用當(dāng)前的 JDK 時(shí),不需要任何附加包。大多數(shù)的 JTA 相關(guān)類都在 javax.transactionjavax.transaction.xa 中。

    您需要用于 DB2 UDB 和 Informix Dynamic Server 的 JDBC 驅(qū)動(dòng)程序。您將需要 Type 4 JDBC 用于 Informix Dynamic Server。DB2 要求您來選擇需要哪個(gè) JDBC 驅(qū)動(dòng)程序。有 Type 2、3 和 4 JDBC。在用 JTA 進(jìn)行編程時(shí),您必須使用 Type 2 或 4 JDBC 驅(qū)動(dòng)程序。為了方便,本文中所演示的所有例子都使用 Type 4 JDBC 驅(qū)動(dòng)程序用于 DB2。(關(guān)于各驅(qū)動(dòng)程序之間差別的解釋,請查閱手冊。)

    以上描述說明了應(yīng)用程序服務(wù)器(Application Server)或事務(wù)管理器(Transaction Manager)的存在。在下面的例子中,您不會(huì)看到“外部”應(yīng)用程序服務(wù)器(Application Server),因?yàn)橐呀?jīng)使用 DB2XADataSource 和 IfxXADataSource 類直接將之構(gòu)建到您的應(yīng)用程序中了。如果您使用一個(gè)真正的應(yīng)用程序服務(wù)器(Application Server),那么該應(yīng)用程序服務(wù)器將使用這些類來連接到數(shù)據(jù)庫的本地 XA 調(diào)用。

    下面的例子(清單 3)演示了一個(gè)小型應(yīng)用程序,該應(yīng)用程序使用 JTA 實(shí)現(xiàn)兩階段提交(Two-Phase-Commit)協(xié)議。該例子并不完整,是為了讓代碼更加易讀。

    清單 3. 兩階段提交的應(yīng)用程序

    
     19 import java.io.BufferedReader;
     20 import java.io.FileInputStream;
     21 import java.io.IOException;
     22 import java.io.InputStreamReader;
     23
     24 import java.sql.Connection;
     25 import java.sql.SQLException;
     26 import java.sql.Statement;
     27
     28 import java.util.Properties;
     29
     30 import javax.sql.XAConnection;
     31 import javax.transaction.xa.XAException;
     32 import javax.transaction.xa.XAResource;
     33 import javax.transaction.xa.Xid;
     34
     35 import com.ibm.db2.jcc.DB2XADataSource;
     36 import com.ibm.db2.jcc.DB2Xid;
     37
     38 import com.informix.jdbcx.IfxXADataSource;
     39 import com.informix.jdbcx.IfxXid;
    

    在第 19-39 行中,您看到了該應(yīng)用程序中所使用的所有類。大多數(shù)類是您所知道的。第 30-33 行中導(dǎo)入的類是使用 JTA 所必要的。同樣有意思的是第 35、36 和 38、39 行中的數(shù)據(jù)庫供應(yīng)商的特定類。xyzXADataSource 類包含了用于啟用兩階段提交協(xié)議的本地 XA 代碼。

    
     44 class DBX {
     45
     46     private Properties props;
     47     private String propertyfile = "jtadb2ifmx.properties";
     48
     56     DBX () {
     57
     58         Connection      db2con = null;
     59         Connection      ifxcon = null;
     60         DB2XADataSource db2ds = null;
     61         IfxXADataSource ifxds = null;
     62         Xid             db2xid = null;
     63         Xid             ifxxid = null;
     64         XAConnection    db2xacon = null;
     65         XAConnection    ifxxacon = null;
     66         XAResource      db2xares = null;
     67         XAResource      ifxxares = null;
     68
     69
     70         // read the properties
     71         props = new Properties ();
     72
     73         try {
     74             props.load (new FileInputStream (propertyfile));
     75         }
     76         catch (IOException io) {
     77             System.err.println ("Error while accessing the properties file (" +
     78                                 propertyfile + "). Abort.");
     79             System.exit (1);
     80         }
    

    DBX 類僅僅包含一個(gè)私有成員,用于負(fù)責(zé)屬性文件。在該文件中,有一些數(shù)據(jù)庫特定的設(shè)置,例如到引擎的端口或登錄信息。

    該類的構(gòu)造函數(shù)實(shí)例化了 SQL 和 XA 相關(guān)類:

    • Connection: 表示到數(shù)據(jù)庫的傳統(tǒng) SQL(JDBC)連接。
    • DB2XADataSourceIfxXADataSource: 這些類包含到數(shù)據(jù)庫的本地 XA 調(diào)用。使用這些類來啟用兩階段提交協(xié)議(Two-Phase-Commit-Protocol)。如果有一個(gè)應(yīng)用程序服務(wù)器(Application Server),就不需要在程序中處理這些類,因?yàn)閼?yīng)用程序服務(wù)器(Application Server)封裝樂應(yīng)用程序的這部分。
    • Xid: 指一個(gè) XA 事務(wù)。本例中,使用了兩個(gè)不同的數(shù)據(jù)庫,所以需要兩個(gè)不同的 Xid —— 每個(gè)數(shù)據(jù)庫連接(分支)一個(gè)。
    • XAConnection: JTA 中的一部分。該類允許您啟動(dòng)(提交、準(zhǔn)備提交 ...)分布式事務(wù)(Distributed Transaction)。
    • XAResource: 該資源指的是應(yīng)用程序服務(wù)器(Application Server)所提供的一個(gè)服務(wù)。同樣,本例中,我們不使用應(yīng)用程序服務(wù)器(Application Server)。因此,必須在該應(yīng)用程序中進(jìn)行創(chuàng)建和初始化。

    
     83         db2ds = initDB2XADataSource ();
     84         ifxds = initIfxXADataSource ();
    

    這些代碼行調(diào)用一個(gè)方法來設(shè)置 XADataSource(參見下面)。

    
    360     IfxXADataSource initIfxXADataSource () {
    361
    362         System.out.print ("Create an IDS XA data source: ");
    363         IfxXADataSource ds = new IfxXADataSource ();
    364         ds.setDescription ("IDS XA data source");
    365         ds.setServerName (props.getProperty ("ifx.connection.instancename"));
    366         ds.setIfxIFXHOST (props.getProperty ("ifx.connection.host"));
    367         ds.setPortNumber (Integer.parseInt
    368             (props.getProperty ("ifx.connection.port")));
    369         ds.setDatabaseName (props.getProperty ("ifx.connection.databasename"));
    370
    371         System.out.println ("Okay.");
    372         return ds;
    373     }
    

    為了方便,這里同時(shí)演示了用于 XADataSource 的 IDS 和 DB2 設(shè)置,因?yàn)樗鼈兪窒嗨啤?

    在安裝 IfxDataSource(第 363 行)之后,需要將多個(gè)設(shè)置指定到數(shù)據(jù)源對象。這些設(shè)置是從屬性文件讀取的。在設(shè)置傳統(tǒng)的 JDBC 數(shù)據(jù)庫連接時(shí),所做的這些設(shè)置可以與數(shù)據(jù)庫 URL 相比。請注意,沒有將任何登錄信息指定給數(shù)據(jù)源對象。登錄信息仍然是數(shù)據(jù)庫連接本身中的一部分。

    正如上面所提到的,如果存在應(yīng)用程序服務(wù)器(Application Server),還可以由它來進(jìn)行這一初始化。

    在用正確的參數(shù)初始化 XADataSource 之后,就將 XADataSource 返回給方法調(diào)用者。

    
     85         db2xacon = initDB2XAConnection (db2ds);
     86         ifxxacon = initIfxXAConnection (ifxds);
    

    在第 85 和 86 行的代碼中,創(chuàng)建了到數(shù)據(jù)庫的 XA Connection。下面描述了如何初始化這些 XA Connection。

    
    329     XAConnection initIfxXAConnection (IfxXADataSource ifxdatasource) {
    330
    331         XAConnection xacon = null;
    332
    333
    334         try {
    335             System.out.print ("Set up IDS XA connection: ");
    336             xacon = ifxdatasource.getXAConnection (
    337                 props.getProperty ("ifx.connection.username"),
    338                 props.getProperty ("ifx.connection.password"));
    339
    340             System.out.println ("Okay.");
    341         }
    342         catch (SQLException e) {
    343             sqlerr (e);
    344         }
    345
    346         return xacon;
    347     }
    

    為了設(shè)置 XAConnection,要使用前面初始化的 DataSource 對象。第 336 行使用 XADataSource 創(chuàng)建了 XAConnection。為了完成 XAConnection,只需要將身份驗(yàn)證信息傳遞給該對象。

    
     87         db2xares = initXAResource (db2xacon);
     88         ifxxares = initXAResource (ifxxacon);
    

    現(xiàn)在,您準(zhǔn)備創(chuàng)建 XAResource 對象了。這些對象將允許您操作兩階段提交(Two-Phase-Commit)。

    
    388     XAResource initXAResource (XAConnection xacon) {
    389
    390         XAResource xares = null;
    391
    392
    393         try {
    394             System.out.print ("Setting up a XA resource: ");
    395             xares = xacon.getXAResource ();
    396             System.out.println ("Okay.");
    397         }
    398         catch (SQLException e) {
    399             sqlerr (e);
    400         }
    401
    402         return xares;
    403     }
    

    XAResource 對象的安裝沒有什么特別的。該對象是通過調(diào)用 XAConnection 中的 getXAResource() 來創(chuàng)建的。

    在完成所有關(guān)于 XA 的準(zhǔn)備之后,就創(chuàng)建到數(shù)據(jù)庫的 JDBC 連接。

    
     89         db2con = getDatabaseConnection (db2xacon);
     90         ifxcon = getDatabaseConnection (ifxxacon);
    

    getDatabaseConnection() 方法中,建立了一個(gè) JDBC 數(shù)據(jù)庫連接。

    
    250     Connection getDatabaseConnection (XAConnection xacon) {
    251
    252         Connection con = null;
    253
    254         try {
    255             System.out.print ("Establish database connection: ");
    256             con = xacon.getConnection ();
    257             System.out.println ("Okay.");
    258         }
    259         catch (SQLException e) {
    260             sqlerr (e);
    261         }
    262
    263         return con;
    264     }
    

    這看上去有些混亂。既然已經(jīng)在第 336 行中設(shè)置了 XAConnection,我們?yōu)楹芜€需要 JDBC 連接呢?我們?yōu)楹稳匀恍枰粋€(gè)“傳統(tǒng)”連接的理由是所有其他 JDBC 操作和類(Statement、ResultSet ...)都基于或使用 Connection 對象。如果您看一看 JDBC 類的層次結(jié)構(gòu)圖,將會(huì)發(fā)現(xiàn) XAConnection 并非是 Connection,反之亦然。XAConnection(實(shí)際上,它是 ConnectionPool 的子類)使用 Connection(層次化)。

    
     93         db2xid = createDB2XID ();
     94         ifxxid = createIfxXID ();
    

    啟動(dòng) XA 事務(wù)之前的最后一步就是為數(shù)據(jù)庫創(chuàng)建 XA ID 對象。在分布式事務(wù)(Distributed Transaction)中進(jìn)行操作時(shí),總是要使用這個(gè) xid

    
    183     Xid createIfxXID () {
    184
    185         Xid xid = null;
    186
    187         byte [] gid = new byte[1];
    188         byte [] bid = new byte[1];
    189
    190         gid[0] =
    191             (Byte.decode (props.getProperty ("xid.global"))).byteValue ();
    192         bid[0] =
    193             (Byte.decode (props.getProperty ("xid.branch.ifx"))).byteValue ();
    194
    195         System.out.print ("Creating an XID (" + Byte.toString (gid[0]) + ", " +
    196                           Byte.toString (bid[0]) + ") for Informix: ");
    197
    198         xid = new IfxXid (0, gid, bid);
    199         System.out.println ("Okay.");
    200         return xid;
    201     }
    

    createIfxXID 方法創(chuàng)建一個(gè) XID(這里:用于 IDS 連接)。正如“兩階段提交協(xié)議簡介”小節(jié)中提到的,XA 事務(wù)包含定義該事務(wù)的兩個(gè)元素。上面例子中的重要部分在第 198 行中。IDS XID 是同三個(gè)參數(shù)創(chuàng)建的。第一個(gè)參數(shù)是 format ID,它描述在什么格式中構(gòu)建分布式事務(wù)(Distributed Transaction)。您可以省略這一格式信息。第二個(gè)參數(shù)定義了全局事務(wù) ID(global transaction ID)。該 ID 對于所有參與數(shù)據(jù)庫來說是惟一的。第三個(gè)參數(shù)表示該全局事務(wù)中的事務(wù)分支。

    在(為 DB2 和 IDS)構(gòu)建 XID 之后,我們可以使用它們來修改單個(gè)事務(wù)中的數(shù)據(jù)。

    
     98         execBranch (db2con, db2xares, db2xid);
     99         execBranch (ifxcon, ifxxares, ifxxid);
    

    execBranch() 方法包含了上面為每個(gè)連接所定義的 XA 事務(wù)中的修改。

    
    215     void execBranch (Connection con, XAResource xares, Xid xid) {
    216
    217         String sql = props.getProperty ("sql.statement");
    218
    219         try {
    220             xares.start (xid, javax.transaction.xa.XAResource.TMNOFLAGS);
    221
    222                 Statement stmt = con.createStatement ();
    223                 stmt.executeUpdate (sql);
    224
    225             xares.end (xid, javax.transaction.xa.XAResource.TMSUCCESS);
    226         }
    227         catch (XAException e) {
    228             System.err.println ("XA exception caught:");
    229             System.err.println ("Cause  : " + e.getCause ());
    230             System.err.println ("Message: " + e.getMessage ());
    231             e.printStackTrace ();
    232         }
    233         catch (SQLException e) {
    234             sqlerr (e);
    235         }
    236     }
    

    第 219-226 行代碼包含了分布式事務(wù)(Distributed Transaction)中為相應(yīng)分支所使用的真正 SQL 語句。分支邊界在第 220 行中以 start 方法開始。傳遞給該方法的參數(shù)就是我們已經(jīng)知道的事務(wù) ID,而第二個(gè)參數(shù)包含了用于該 XA 事務(wù)的一些附加信息。因?yàn)檫@是第一個(gè)兩階段提交(Two-Phase-Commit)協(xié)議操作,所以不需要向該方法傳遞任何特殊信息。TMNOFLAGS 說明了這一事實(shí)。分支邊界終止于第 225 行。標(biāo)志 TMSUCCESS 描述所有操作都成功。

    在 IDS 和 DB2 的分支都執(zhí)行之后,全局事務(wù)就準(zhǔn)備提交這些修改。當(dāng)然,在可以向數(shù)據(jù)庫傳送最后的提交之前,必須詢問數(shù)據(jù)庫是否準(zhǔn)備進(jìn)行提交。

    
    104         if (prepareCommit (db2xares, db2xid) == XAResource.XA_OK &&
    105             prepareCommit (ifxxares, ifxxid) == XAResource.XA_OK) {
    106             // both branches are ready to commit
    107             commitBranch (db2xares, db2xid);
    108             commitBranch (ifxxares, ifxxid);
    109         }
    110         else {
    111             // a resource reported an error
    112             rollbackBranch (db2xares, db2xid);
    113             rollbackBranch (ifxxares, ifxxid);
    114         }
    116     } // end of constructor
    

    第 104 和 105 行通知數(shù)據(jù)庫準(zhǔn)備提交。如果數(shù)據(jù)庫報(bào)告 XAResource.XA_OK,就可以提交整個(gè)事務(wù)。否則,該事務(wù)就將被 ROLLBACK 中止。

    
    417     int prepareCommit (XAResource xares, Xid xid) {
    418
    419         int rc = 0;
    420
    421         System.out.print ("Prepare XA branch (" +
    422             Byte.toString ((xid.getGlobalTransactionId ())[0]) + ", " +
    423             Byte.toString ((xid.getBranchQualifier ())[0]) + "): ");
    424
    425         try {
    426             xares.prepare (xid);
    427         }
    428         catch (XAException e) {
    429             xaerr (e);
    430         }
    431
    432         System.out.println ("Okay.");
    433         return rc;
    434     }
    

    prepareCommit() 方法中最重要的一行在第 426 行中。prepare 方法引起數(shù)據(jù)庫調(diào)用兩階段提交協(xié)議(Two-Phase-Commit)的“第 1 階段”。

    根據(jù)“第 1 階段”的結(jié)果,將提交或中止該分布式事務(wù)(Distributed Transaction)。下面是將用于發(fā)出這些必要操作的兩個(gè)方法。

    
    128     void commitBranch (XAResource xares, Xid xid) {
    129
    130         System.out.print ("Commit XA branch (" +
    131             Byte.toString ((xid.getGlobalTransactionId ())[0]) + ", " +
    132             Byte.toString ((xid.getBranchQualifier ())[0]) + "): ");
    133
    134         try {
    135             // second parameter is 'false' since we have a two phase commit
    136             xares.commit (xid, false);
    137         }
    138         catch (XAException e) {
    139             xaerr (e);
    140         }
    141
    142         System.out.println ("Okay.");
    143     }
    

    如果“第 1 階段”未報(bào)告任何錯(cuò)誤,就在第 136 行中為 xid 所描述的事務(wù)分支提交“第 2 階段”。方法 commit() 中的第二個(gè)參數(shù)區(qū)分單階段或兩階段提交操作。因?yàn)槲覀兙哂幸粋€(gè)兩階段提交操作,所以必須將該值設(shè)置為 false。

    下面的例子展示了如何為數(shù)據(jù)庫回滾事務(wù)分支。

    
    446     void rollbackBranch (XAResource xares, Xid xid) {
    447
    448         System.out.print ("Rollback XA branch (" +
    449             Byte.toString ((xid.getGlobalTransactionId ())[0]) + ", " +
    450             Byte.toString ((xid.getBranchQualifier ())[0]) + "): ");
    451
    452         try {
    453             xares.rollback (xid);
    454         }
    455         catch (XAException e) {
    456             xaerr (e);
    457         }
    458
    459         System.out.println ("Okay.");
    460     }
    

    問題解答
    本文中的例子演示了如何在 Java 中使用 JTA 實(shí)現(xiàn)兩階段提交(Two-Phase-Commit)協(xié)議。在該應(yīng)用程序中,如果一個(gè)事務(wù)分支報(bào)告了錯(cuò)誤,您就要負(fù)責(zé)進(jìn)行錯(cuò)誤處理。但是“兩階段提交協(xié)議簡介”小節(jié)中提到仍然存在一個(gè)問題,那就是如果第 2 階段中一個(gè)事務(wù)分支發(fā)生故障,該怎么辦呢?

    如果再次查看程序代碼,您可以看到在“第 1 階段”和“第 2 階段”之間有一個(gè)很小的時(shí)間間隔。在這一時(shí)間間隔中,出于某種理由,其中某一參與數(shù)據(jù)庫可能崩潰。如果發(fā)生了,我們將陷入分布式事務(wù)已經(jīng)部分提交的情形中。

    假定下列情形:在“第 1 階段”之后,您從 DB2 和 IDS 數(shù)據(jù)庫中都收到了“okay”。在下一步中,應(yīng)用程序成功提交了 DB2 的事務(wù)分支。接著,應(yīng)用程序通知 DB2 事務(wù)分支提交事務(wù)?,F(xiàn)在,在應(yīng)用程序可以通知 IDS 事務(wù)分支提交它這一部分之前,IDS 引擎由于斷電發(fā)生崩潰。這就是一種部分提交全局事務(wù)的情形。您現(xiàn)在該怎么辦呢?

    在重啟之后,DB2 和 IDS 都將嘗試恢復(fù)打開的事務(wù)分支。該引擎等待來自應(yīng)用程序的提示如何做。如果應(yīng)用程序沒有準(zhǔn)備重新發(fā)送“第 2 階段”的提交,該事務(wù)分支將被引擎所啟動(dòng)的試探性回滾中止。這是非常糟糕的,因?yàn)檫@將使該全局事務(wù)處于不一致狀態(tài)。

    一種解決方案是用一個(gè)小型應(yīng)用程序連接引擎中打開的事務(wù)分支,并通知引擎提交或回滾這一打開的事務(wù)。如果您使用 IDS 作為后端,那么還有一個(gè)隱藏的 onmode 標(biāo)志,允許您結(jié)束打開的事務(wù)分支。(onmode -Z xid)。

    在 DB2 UDB 中,您可以發(fā)出 LIST INDOUBT TRANSACTIONS 來獲得打開的 XA 事務(wù)的有關(guān)信息。您必須查看 DB2 Information Center 中的描述來解決該問題。

    上面描述的情形是一個(gè)很好的例子,也是使用應(yīng)用程序服務(wù)器(Application Server)或事務(wù)監(jiān)控器(Transaction Monitor)的理由。在使用一個(gè)中間層服務(wù)器時(shí),就由該服務(wù)器負(fù)責(zé)保持事情正常。

    備選方案
    清單 1   演示了在應(yīng)用程序中從數(shù)據(jù)庫讀取數(shù)據(jù)并處理結(jié)果的可行方法。如果您的應(yīng)用程序是“只讀”應(yīng)用程序,IBM? 就提供了另一種解決方案,稱作 WebSphere? Information Integrator。WebSphere Information Integrator 使用來自 DB2 UDB(或 DB2 Data Joiner、DB2 Relational Connect)的聯(lián)邦數(shù)據(jù)庫技術(shù),以將多個(gè)數(shù)據(jù)庫(通常:數(shù)據(jù)源)虛擬化(virtualize)到一個(gè)數(shù)據(jù)庫中。不同的、非本地的數(shù)據(jù)庫中的表都鏈接到 DB2 UDB 中。該操作對于客戶機(jī)應(yīng)用程序是完全透明的。客戶機(jī)可以訪問其他數(shù)據(jù)庫中的所有遠(yuǎn)程表,就像它們是本地 DB2 UDB 表一樣。正如 清單 1  中引用的,不再需要連接兩個(gè)數(shù)據(jù)庫。到 DB2 UDB 的單個(gè)連接就已經(jīng)足夠了,因?yàn)?DB2 中可以看到 IDS 數(shù)據(jù)庫中的所有表。

    目前,WebSphere Information Integrator 不支持兩階段提交,然而,將來的版本將支持兩階段提交協(xié)議;這將帶來實(shí)現(xiàn)企業(yè)應(yīng)用程序的新方法。

    參考資料

    關(guān)于作者
    Uwe Weber 是一位 Informix 和 DB2 UDB 方面的 IT 專家。他居住在德國的慕尼黑。Uwe 的 IT 經(jīng)歷始于 1997 年,從那時(shí)起,他作為一名 Informix 產(chǎn)品講師開始在 Informix 工作。IBM 于 2001 年收購 Informix 之后,他調(diào)去了技術(shù)預(yù)售部門,與 EMEA Central 的客戶一起工作。

    posted on 2006-02-20 14:53 TrampEagle 閱讀(470) 評(píng)論(0)  編輯  收藏 所屬分類: datebase
    主站蜘蛛池模板: 日本最新免费网站| 亚洲国产精品一区二区久久| 91热成人精品国产免费| 麻豆69堂免费视频| 亚洲精品123区在线观看| 久久久综合亚洲色一区二区三区 | 亚洲中文字幕无码久久综合网| 无码人妻一区二区三区免费| 亚在线观看免费视频入口| 黄色三级三级免费看| 久久精品亚洲AV久久久无码| 亚洲一区二区电影| 中文字幕在线亚洲精品| 免费a级毛片网站| 大地资源免费更新在线播放| 免费无码VA一区二区三区| 99视频在线观看免费| 一进一出60分钟免费视频| 婷婷国产偷v国产偷v亚洲| 亚洲色偷偷综合亚洲AV伊人蜜桃 | 99免费观看视频| 三年片在线观看免费西瓜视频| 亚洲av第一网站久章草| 亚洲精品第一国产综合亚AV| 2020年亚洲天天爽天天噜| 亚洲专区一路线二| 91嫩草私人成人亚洲影院| 久久亚洲日韩看片无码| 色播亚洲视频在线观看| 91亚洲精品第一综合不卡播放| 亚洲av网址在线观看| 亚洲AV日韩AV永久无码绿巨人| 日韩亚洲人成在线综合日本| 久久亚洲国产午夜精品理论片| 亚洲精品无码鲁网中文电影| 国产亚洲精aa成人网站| 亚洲一区精品无码| 亚洲成av人在线视| 亚洲人成影院在线| 亚洲最大在线视频| 亚洲娇小性xxxx|