[JTA] Java事务api
生活随笔
收集整理的這篇文章主要介紹了
[JTA] Java事务api
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
JTA和JTS
Java事務(wù)API(JTA:Java Transaction API)和它的同胞Java事務(wù)服務(wù)(JTS:Java Transaction Service),為J2EE平臺提供了分布式事務(wù)服務(wù)(distributed transaction)。 一個分布式事務(wù)(distributed transaction)包括一個事務(wù)管理器(transaction manager)和一個或多個資源管理器(resource manager)。 一個資源管理器(resource manager)是任意類型的持久化數(shù)據(jù)存儲。 事務(wù)管理器(transaction manager)承擔著所有事務(wù)參與單元者的相互通訊的責任。JTA與JDBC
JTA事務(wù)比JDBC事務(wù)更強大。一個JTA事務(wù)可以有多個參與者,而一個JDBC事務(wù)則被限定在一個單一的數(shù)據(jù)庫連接。下列任一個Java平臺的組件都可以參與到一個JTA事務(wù)中:JDBC連接、JDO PersistenceManager 對象、JMS 隊列、JMS 主題、企業(yè)JavaBeans(EJB)、一個用J2EE Connector Architecture 規(guī)范編譯的資源分配器。劃分
要用JTA來劃分一個事務(wù),應(yīng)用程序調(diào)用javax.transaction.UserTransaction接口中的方法。 示例4顯示了一個典型的JNDI搜索的UseTransaction對象。 import javax.transaction.*; import javax.naming.*; // ... InitialContext ctx = new InitialContext(); Object txObj = ctx.lookup(";java:comp/UserTransaction";); UserTransaction utx = (UserTransaction) txObj; 應(yīng)用程序有了UserTransaction對象的引用之后,就可以象示例5那樣來起動事務(wù)。| utx.begin(); // ... DataSource ds = obtainXADataSource(); Connection conn = ds.getConnection(); pstmt = conn.prepareStatement(";UPDATE MOⅥES ...";); pstmt.setString(1, ";Spinal Tap";); pstmt.executeUpdate(); // ... utx.commit(); // ... |
使用
應(yīng)用程序調(diào)用begin()來起動事務(wù),即可調(diào)用commit()也可以調(diào)用rollback()來結(jié)束事務(wù)。 開發(fā)人員經(jīng)常使用JDBC來作為DAO類中的底層數(shù)據(jù)操作。 如果計劃使用JTA來劃分事務(wù),你將需要一個實現(xiàn)了javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驅(qū)動。 實現(xiàn)了這些接口的驅(qū)動將有能力參與到JTA事務(wù)中。 一個XADataSource對象是一個XAConnection對象的工廠。XAConnections是參與到JTA事務(wù)中的連接。你需要使用應(yīng)用程序服務(wù)器管理工具來建立XADataSource對象。特殊指令
對于特殊的指令請參考應(yīng)用程序服務(wù)器文檔和JDBC驅(qū)動文檔。 J2EE應(yīng)用程序使用JNDI來查找數(shù)據(jù)源。 一旦應(yīng)用程序有了一個數(shù)據(jù)源對象的引用,這會調(diào)用javax.sql.DataSource.getConnection()來獲得數(shù)據(jù)庫的連接。連接
XA連接區(qū)別于非XA連接。要記住的是XA連接是一個JTA事務(wù)中的參與者。這就意味著XA連接不支持JDBC的自動提交特性。也就是說應(yīng)用程序不必在XA連接上調(diào)用java.sql.Connection.commit()或java.sql.Connection.rollback()。相反,應(yīng)用程序應(yīng)該使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().DAO類總結(jié)
我們已經(jīng)討論了JDBC和JTA是怎樣劃分事務(wù)的。每一種方法都有它的優(yōu)點,因此你需要決定為你的應(yīng)用程序選擇一個最適應(yīng)的方法。在我們團隊許多最近的對于事務(wù)劃分的項目中使用JDBC API來創(chuàng)建DAO類。 這DAO類總結(jié)如下: ⒈事務(wù)劃分代碼被嵌入到DAO類內(nèi)部 ⒉DAO類使用JDBC API來進行事務(wù)劃分 ⒊調(diào)用者沒有劃分事務(wù)的方法 ⒋事務(wù)范圍被限定在一個單一的JDBC連接應(yīng)用程序
JDBC事務(wù)對復(fù)雜的企業(yè)應(yīng)用程序不總是有效的。如果你的事務(wù)將跨越多個DAO對象或多個數(shù)據(jù)庫,那么下面的實現(xiàn)策略可能會更恰當: ⒈用JTA對事務(wù)進行劃分 ⒉事務(wù)劃分代碼被DAO分開 ⒊調(diào)用者承擔劃分事務(wù)的責任 ⒋DAO參與一個全局的事務(wù)中 JDBC方法由于它的簡易性而具有吸引力,JTA方法提供了更多靈活性。你選擇什么樣的實現(xiàn)將依賴于你的應(yīng)用程序的特定需求。 JTA(Java Transaction API) 為 J2EE 平臺提供了分布式事務(wù)服務(wù)。 要用 JTA 進行事務(wù)界定,應(yīng)用程序要調(diào)用 javax.transaction.UserTransaction 接口中的方法。例如: utx.begin(); // ... DataSource ds = obtainXADataSource(); Connection conn = ds.getConnection(); pstmt = conn.prepareStatement("UPDATE MOⅥES ..."); pstmt.setString(1,"Spinal Tap"); pstmt.executeUpdate(); // ... utx.commit();注意
讓我們來關(guān)注下面的話: “用 JTA 界定事務(wù),那么就需要有一個實現(xiàn) javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驅(qū)動程序。一個實現(xiàn)了這些接口的驅(qū)動程序?qū)⒖梢詤⑴c JTA 事務(wù)。一個 XADataSource 對象就是一個 XAConnection 對象的工廠。XAConnection s 是參與 JTA 事務(wù)的 JDBC 連接。” 要使用JTA事務(wù),必須使用XADataSource來產(chǎn)生數(shù)據(jù)庫連接,產(chǎn)生的連接為一個XA連接。 XA連接(javax.sql.XAConnection)和非XA(java.sql.Connection)連接的區(qū)別在于:XA可以參與JTA的事務(wù),而且不支持自動提交。 Note: Oracle,Sybase,DB2,SQL Server等大型數(shù)據(jù)庫才支持XA,支持分布事務(wù)。 My SQL 連本地都支持不好,更別說分布事務(wù)了。 MySql 在5.0的版本后增加了對xa的支持2實例
用XADataSource產(chǎn)生的XAConnection它擴展了一個getXAResource()方法,事務(wù)通過這個方法把它加入到事務(wù)容器中進行管理.對于調(diào)用者來說,根本看不到事務(wù)是如何管理的,你只要聲明開始事務(wù),告訴容器我下面的操作要求事務(wù)參與了,最后告訴事務(wù)說到這兒可以提交或回滾了,別的都是暗箱操作。 首先,實現(xiàn)一個Xid類用來標識事務(wù): 在使用JTA之前,你必須首先實現(xiàn)一個Xid類用來標識事務(wù)(在普通情況下這將由事務(wù)管理程序來處理)。Xid包含三個元素:formatID、gtrid(全局事務(wù)標識符)和bqual(分支修飾詞標識符)。 下面的例子說明Xid的實現(xiàn): import javax.transaction.xa.*; public class MyXid implements Xid { protected int formatId; protected byte gtrid[]; protected byte bqual[]; public MyXid() { } public MyXid(int formatId,byte gtrid[],byte bqual[]) { this.formatId = formatId; this.gtrid = gtrid; this.bqual = bqual; } public int getFormatId() { return formatId; } public byte[] getBranchQualifier() { return bqual; } public byte[] getGlobalTransactionId() { return gtrid; } } 其次,創(chuàng)建數(shù)據(jù)源: 其次,你需要創(chuàng)建一個你要使用的數(shù)據(jù)庫的數(shù)據(jù)源: public DataSource getDataSource() throws SQLException { SQLServerDataSource xaDS = new com.merant.datadirect.jdbcx.sqlserver.SQLServerDataSource(); xaDS.setDataSourceName("SQLServer"); xaDS.setServerName("server"); xaDS.setPortNumber(1433); xaDS.setSelectMethod("cursor"); return xaDS; } 例1“這個例子是用“兩步提交協(xié)議”來提交一個事務(wù)分支: XADataSource xaDS; XAConnection xaCon; XAResource xaRes; Xid xid; Connection con; Statement stmt; int ret; xaDS = getDataSource(); xaCon = xaDS.getXAConnection("jdbc_user","jdbc_password"); xaRes = xaCon.getXAResource(); con = xaCon.getConnection(); stmt = con.createStatement(); xid = new MyXid(100,new byte[]{0x01},new byte[]{0x02}); try { xaRes.start(xid,XAResource.TMNOFLAGS); stmt.executeUpdate("insert into test_table values (100)"); xaRes.end(xid,XAResource.TMSUCCESS); ret = xaRes.prepare(xid); if (ret == XAResource.XA_OK) { xaRes.commit(xid,false); } } catch (XAException e) { e.printStackTrace(); } finally { stmt.close(); con.close(); xaCon.close(); } 因為所有這些例子中的初始化代碼相同或者非常相似,僅僅是一些重要的地方的代碼由不同。 例2:這個例子,與例1相似,說明了一個返回過程: xaRes.start(xid,XAResource.TMNOFLAGS); stmt.executeUpdate("insert into test_table values (100)"); xaRes.end(xid,XAResource.TMSUCCESS); ret = xaRes.prepare(xid); if (ret == XAResource.XA_OK) { xaRes.rollback(xid); } 例3:這個例子說明一個分布式事務(wù)分支如何中止,讓相同的連接做本地事務(wù)處理,以及它們稍后該如何繼續(xù)這個分支。分布式事務(wù)的兩步提交作用不影響本地事務(wù)。 xid = new MyXid(100,new byte[]{0x01},new byte[]{0x02}); xaRes.start(xid,XAResource.TMNOFLAGS); stmt.executeUpdate("insert into test_table values (100)"); xaRes.end(xid,XAResource.TMSUSPEND); 這個更新在事務(wù)范圍之外完成,所以它不受XA返回影響。 stmt.executeUpdate("insert into test_table2 values (111)"); xaRes.start(xid,XAResource.TMRESUME); stmt.executeUpdate("insert into test_table values (200)"); xaRes.end(xid,XAResource.TMSUCCESS); ret = xaRes.prepare(xid); if (ret == XAResource.XA_OK) { xaRes.rollback(xid); } 例4:這個例子說明一個XA資源如何分擔不同的事務(wù)。創(chuàng)建了兩個事務(wù)分支,但是它們不屬于相同的分布式事務(wù)。JTA允許XA資源在第一個分支上做一個兩步提交,雖然這個資源仍然與第二個分支相關(guān)聯(lián)。 xid1 = new MyXid(100,new byte[]{0x01},new byte[]{0x02}); xid2 = new MyXid(100,new byte[]{0x11},new byte[]{0x22}); xaRes.start(xid1,XAResource.TMNOFLAGS); stmt.executeUpdate("insert into test_table1 values (100)"); xaRes.end(xid1,XAResource.TMSUCCESS); xaRes.start(xid2,XAResource.TMNOFLAGS); ret = xaRes.prepare(xid1); if (ret == XAResource.XA_OK) { xaRes.commit(xid2,false); } stmt.executeUpdate("insert into test_table2 values (200)"); xaRes.end(xid2,XAResource.TMSUCCESS); ret = xaRes.prepare(xid2); if (ret == XAResource.XA_OK) { xaRes.rollback(xid2); } 例5:這個例子說明不同的連接上的事務(wù)分支如何連接成為一個單獨的分支,如果它們連接到相同的資源管理程序。這個特點改善了分布式事務(wù)的效率,因為它減少了兩步提交處理的數(shù)目。兩個連接到數(shù)據(jù)庫服務(wù)器上的XA將被創(chuàng)建。每個連接創(chuàng)建它自己的XA資源,正規(guī)的JDBC連接和語句。在第二個XA資源開始一個事務(wù)分支之前,它將察看是否使用和第一個XA資源使用的是同一個資源管理程序。如果這是實例,它將加入在第一個XA連接上創(chuàng)建的第一個分支,而不是創(chuàng)建一個新的分支。稍后,這個事務(wù)分支使用XA資源來準備和提交。 xaDS = getDataSource(); xaCon1 = xaDS.getXAConnection("jdbc_user","jdbc_password"); xaRes1 = xaCon1.getXAResource(); con1 = xaCon1.getConnection(); stmt1 = con1.createStatement(); xid1 = new MyXid(100,new byte[]{0x01},new byte[]{0x02}); xaRes1.start(xid1,XAResource.TMNOFLAGS); stmt1.executeUpdate("insert into test_table1 values (100)"); xaRes1.end(xid,XAResource.TMSUCCESS); xaCon2 = xaDS.getXAConnection("jdbc_user","jdbc_password"); xaRes2 = xaCon1.getXAResource(); con2 = xaCon1.getConnection(); stmt2 = con1.createStatement(); if (xaRes2.isSameRM(xaRes1)) { xaRes2.start(xid1,XAResource.TMJOIN); stmt2.executeUpdate("insert into test_table2 values (100)"); xaRes2.end(xid1,XAResource.TMSUCCESS); } else { xid2 = new MyXid(100,new byte[]{0x01},new byte[]{0x03}); xaRes2.start(xid2,XAResource.TMNOFLAGS); stmt2.executeUpdate("insert into test_table2 values (100)"); xaRes2.end(xid2,XAResource.TMSUCCESS); ret = xaRes2.prepare(xid2); if (ret == XAResource.XA_OK) { xaRes2.commit(xid2,false); } } ret = xaRes1.prepare(xid1); if (ret == XAResource.XA_OK) { xaRes1.commit(xid1,false); } 例6:這個例子說明在錯誤恢復(fù)的階段,如何恢復(fù)準備好的或者快要完成的事務(wù)分支。它首先試圖返回每個分支;如果它失敗了,它嘗試著讓資源管理程序丟掉關(guān)于事務(wù)的消息。 MyXid[] xids; xids = xaRes.recover(XAResource.TMSTARTRSCAN | XAResource.TMENDRSCAN); for (int i=0; xids!=null && i try { xaRes.rollback(xids[i]); } catch (XAException ex) { try { xaRes.forget(xids[i]); } catch (XAException ex1) { System.out.println("rollback/forget failed: " + ex1.errorCode); } } } [摘自百度文庫]轉(zhuǎn)載于:https://www.cnblogs.com/kentyouyou/p/3468670.html
總結(jié)
以上是生活随笔為你收集整理的[JTA] Java事务api的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于visual Studio2013解
- 下一篇: Java从入门到精通——调错篇之SVN