鷹翔宇空

          學習和生活

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

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

          簡介
          在現代企業環境中,用多個數據庫和多種品牌的數據庫來存儲公司數據已經不足為奇。最終,這些數據將會在不同數據庫外進行比較、合并。

          如果您有一個異構的數據庫環境,并且計劃將不同數據庫中的數據收集到一個單獨的應用程序中,那么您就應該可以使用傳統技術執行該任務。在使用 Java 時,您將通過 JDBC 處理所有的數據庫操作。清單 1 展示了在 Java 應用程序中如何連接 DB2 UDB 和 IDS 的代碼片斷。

          清單 1. 使用 JDBC 建立到不同數據庫的連接
          
            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 }
          

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

          但是如果您需要在單個事務中封裝到 DB2 和 IDS 表的新一行的 insert,要做什么呢?
          意思就是說,如果其中一條 insert 語句失敗了,就應該將數據庫(這里:兩種數據庫!)的初始狀態恢復為客戶機未執行任何動作的狀態。該行為可以通過使用兩階段提交(Two-Phase-Commit)協議完成。這一標準化協議描述了如何實現分布式事務(XA)分布式工作單元(Distributed Unit of Work,DUOW)的技術,以達到跨數據庫系統的一致狀態(根據 ACID)。

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

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

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

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

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

          圖 1. 兩階段提交中的時間線和應用程序流

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

          清單 2. 非“兩階段提交”的應用程序
          
            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 和事務管理器(TM)
          Java Transaction API 允許您操作應用程序中的分布式事務(Distributed Transaction)。JTA 中有一組方法,它將傳統的 JDBC 調用封裝到了兩階段提交(Two-Phase-Commit)協議中。

          在異構環境中,您通常會發現一個事務管理器(Transaction Manager),負責處理分布式事務。(實際上,事務管理器可以完成大量的工作負載平衡。)因此,不僅存在到數據庫的直接連接,還有到事務管理器(Transaction Manager)的連接。這就是 JTA 發揮作用的地方:JTA 是 Java 應用程序和事務管理器(Transaction Manager)之間的接口。圖 2 演示了一個包含分布式事務的典型環境。

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

          圖 2. 三層架構

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

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

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

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

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

          以上描述說明了應用程序服務器(Application Server)或事務管理器(Transaction Manager)的存在。在下面的例子中,您不會看到“外部”應用程序服務器(Application Server),因為已經使用 DB2XADataSource 和 IfxXADataSource 類直接將之構建到您的應用程序中了。如果您使用一個真正的應用程序服務器(Application Server),那么該應用程序服務器將使用這些類來連接到數據庫的本地 XA 調用。

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

          清單 3. 兩階段提交的應用程序

          
           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 行中,您看到了該應用程序中所使用的所有類。大多數類是您所知道的。第 30-33 行中導入的類是使用 JTA 所必要的。同樣有意思的是第 35、36 和 38、39 行中的數據庫供應商的特定類。xyzXADataSource 類包含了用于啟用兩階段提交協議的本地 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 類僅僅包含一個私有成員,用于負責屬性文件。在該文件中,有一些數據庫特定的設置,例如到引擎的端口或登錄信息。

          該類的構造函數實例化了 SQL 和 XA 相關類:

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

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

          這些代碼行調用一個方法來設置 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     }
          

          為了方便,這里同時演示了用于 XADataSource 的 IDS 和 DB2 設置,因為它們十分相似。

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

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

          在用正確的參數初始化 XADataSource 之后,就將 XADataSource 返回給方法調用者。

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

          在第 85 和 86 行的代碼中,創建了到數據庫的 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     }
          

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

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

          現在,您準備創建 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 對象的安裝沒有什么特別的。該對象是通過調用 XAConnection 中的 getXAResource() 來創建的。

          在完成所有關于 XA 的準備之后,就創建到數據庫的 JDBC 連接。

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

          getDatabaseConnection() 方法中,建立了一個 JDBC 數據庫連接。

          
          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     }
          

          這看上去有些混亂。既然已經在第 336 行中設置了 XAConnection,我們為何還需要 JDBC 連接呢?我們為何仍然需要一個“傳統”連接的理由是所有其他 JDBC 操作和類(Statement、ResultSet ...)都基于或使用 Connection 對象。如果您看一看 JDBC 類的層次結構圖,將會發現 XAConnection 并非是 Connection,反之亦然。XAConnection(實際上,它是 ConnectionPool 的子類)使用 Connection(層次化)。

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

          啟動 XA 事務之前的最后一步就是為數據庫創建 XA ID 對象。在分布式事務(Distributed Transaction)中進行操作時,總是要使用這個 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 方法創建一個 XID(這里:用于 IDS 連接)。正如“兩階段提交協議簡介”小節中提到的,XA 事務包含定義該事務的兩個元素。上面例子中的重要部分在第 198 行中。IDS XID 是同三個參數創建的。第一個參數是 format ID,它描述在什么格式中構建分布式事務(Distributed Transaction)。您可以省略這一格式信息。第二個參數定義了全局事務 ID(global transaction ID)。該 ID 對于所有參與數據庫來說是惟一的。第三個參數表示該全局事務中的事務分支。

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

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

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

          
          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 行代碼包含了分布式事務(Distributed Transaction)中為相應分支所使用的真正 SQL 語句。分支邊界在第 220 行中以 start 方法開始。傳遞給該方法的參數就是我們已經知道的事務 ID,而第二個參數包含了用于該 XA 事務的一些附加信息。因為這是第一個兩階段提交(Two-Phase-Commit)協議操作,所以不需要向該方法傳遞任何特殊信息。TMNOFLAGS 說明了這一事實。分支邊界終止于第 225 行。標志 TMSUCCESS 描述所有操作都成功。

          在 IDS 和 DB2 的分支都執行之后,全局事務就準備提交這些修改。當然,在可以向數據庫傳送最后的提交之前,必須詢問數據庫是否準備進行提交。

          
          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 行通知數據庫準備提交。如果數據庫報告 XAResource.XA_OK,就可以提交整個事務。否則,該事務就將被 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 方法引起數據庫調用兩階段提交協議(Two-Phase-Commit)的“第 1 階段”。

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

          
          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 階段”未報告任何錯誤,就在第 136 行中為 xid 所描述的事務分支提交“第 2 階段”。方法 commit() 中的第二個參數區分單階段或兩階段提交操作。因為我們具有一個兩階段提交操作,所以必須將該值設置為 false

          下面的例子展示了如何為數據庫回滾事務分支。

          
          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 實現兩階段提交(Two-Phase-Commit)協議。在該應用程序中,如果一個事務分支報告了錯誤,您就要負責進行錯誤處理。但是“兩階段提交協議簡介”小節中提到仍然存在一個問題,那就是如果第 2 階段中一個事務分支發生故障,該怎么辦呢?

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

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

          在重啟之后,DB2 和 IDS 都將嘗試恢復打開的事務分支。該引擎等待來自應用程序的提示如何做。如果應用程序沒有準備重新發送“第 2 階段”的提交,該事務分支將被引擎所啟動的試探性回滾中止。這是非常糟糕的,因為這將使該全局事務處于不一致狀態。

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

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

          上面描述的情形是一個很好的例子,也是使用應用程序服務器(Application Server)或事務監控器(Transaction Monitor)的理由。在使用一個中間層服務器時,就由該服務器負責保持事情正常。

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

          目前,WebSphere Information Integrator 不支持兩階段提交,然而,將來的版本將支持兩階段提交協議;這將帶來實現企業應用程序的新方法。

          參考資料

          關于作者
          Uwe Weber 是一位 Informix 和 DB2 UDB 方面的 IT 專家。他居住在德國的慕尼黑。Uwe 的 IT 經歷始于 1997 年,從那時起,他作為一名 Informix 產品講師開始在 Informix 工作。IBM 于 2001 年收購 Informix 之后,他調去了技術預售部門,與 EMEA Central 的客戶一起工作。

          posted on 2006-02-20 14:53 TrampEagle 閱讀(471) 評論(0)  編輯  收藏 所屬分類: datebase
          主站蜘蛛池模板: 北票市| 通州市| 奉节县| 甘肃省| 金寨县| 疏勒县| 六安市| 蕉岭县| 上林县| 贡嘎县| 盐亭县| 长武县| 鲁甸县| 黔西县| 桐梓县| 明光市| 鹤岗市| 永仁县| 延津县| 清水县| 电白县| 河西区| 武城县| 安康市| 新昌县| 麻栗坡县| 灵璧县| 麟游县| 凤山市| 舟山市| 赤壁市| 莫力| 抚远县| 方山县| 东宁县| 龙南县| 三明市| 连城县| 张家港市| 津市市| 阜南县|