[JTA] Java事务api
生活随笔
收集整理的這篇文章主要介紹了
[JTA] Java事务api
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
JTA和JTS
Java事務API(JTA:Java Transaction API)和它的同胞Java事務服務(JTS:Java Transaction Service),為J2EE平臺提供了分布式事務服務(distributed transaction)。 一個分布式事務(distributed transaction)包括一個事務管理器(transaction manager)和一個或多個資源管理器(resource manager)。 一個資源管理器(resource manager)是任意類型的持久化數據存儲。 事務管理器(transaction manager)承擔著所有事務參與單元者的相互通訊的責任。JTA與JDBC
JTA事務比JDBC事務更強大。一個JTA事務可以有多個參與者,而一個JDBC事務則被限定在一個單一的數據庫連接。下列任一個Java平臺的組件都可以參與到一個JTA事務中:JDBC連接、JDO PersistenceManager 對象、JMS 隊列、JMS 主題、企業JavaBeans(EJB)、一個用J2EE Connector Architecture 規范編譯的資源分配器。劃分
要用JTA來劃分一個事務,應用程序調用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; 應用程序有了UserTransaction對象的引用之后,就可以象示例5那樣來起動事務。| utx.begin(); // ... DataSource ds = obtainXADataSource(); Connection conn = ds.getConnection(); pstmt = conn.prepareStatement(";UPDATE MOⅥES ...";); pstmt.setString(1, ";Spinal Tap";); pstmt.executeUpdate(); // ... utx.commit(); // ... |
使用
應用程序調用begin()來起動事務,即可調用commit()也可以調用rollback()來結束事務。 開發人員經常使用JDBC來作為DAO類中的底層數據操作。 如果計劃使用JTA來劃分事務,你將需要一個實現了javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驅動。 實現了這些接口的驅動將有能力參與到JTA事務中。 一個XADataSource對象是一個XAConnection對象的工廠。XAConnections是參與到JTA事務中的連接。你需要使用應用程序服務器管理工具來建立XADataSource對象。特殊指令
對于特殊的指令請參考應用程序服務器文檔和JDBC驅動文檔。 J2EE應用程序使用JNDI來查找數據源。 一旦應用程序有了一個數據源對象的引用,這會調用javax.sql.DataSource.getConnection()來獲得數據庫的連接。連接
XA連接區別于非XA連接。要記住的是XA連接是一個JTA事務中的參與者。這就意味著XA連接不支持JDBC的自動提交特性。也就是說應用程序不必在XA連接上調用java.sql.Connection.commit()或java.sql.Connection.rollback()。相反,應用程序應該使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().DAO類總結
我們已經討論了JDBC和JTA是怎樣劃分事務的。每一種方法都有它的優點,因此你需要決定為你的應用程序選擇一個最適應的方法。在我們團隊許多最近的對于事務劃分的項目中使用JDBC API來創建DAO類。 這DAO類總結如下: ⒈事務劃分代碼被嵌入到DAO類內部 ⒉DAO類使用JDBC API來進行事務劃分 ⒊調用者沒有劃分事務的方法 ⒋事務范圍被限定在一個單一的JDBC連接應用程序
JDBC事務對復雜的企業應用程序不總是有效的。如果你的事務將跨越多個DAO對象或多個數據庫,那么下面的實現策略可能會更恰當: ⒈用JTA對事務進行劃分 ⒉事務劃分代碼被DAO分開 ⒊調用者承擔劃分事務的責任 ⒋DAO參與一個全局的事務中 JDBC方法由于它的簡易性而具有吸引力,JTA方法提供了更多靈活性。你選擇什么樣的實現將依賴于你的應用程序的特定需求。 JTA(Java Transaction API) 為 J2EE 平臺提供了分布式事務服務。 要用 JTA 進行事務界定,應用程序要調用 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();注意
讓我們來關注下面的話: “用 JTA 界定事務,那么就需要有一個實現 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驅動程序。一個實現了這些接口的驅動程序將可以參與 JTA 事務。一個 XADataSource 對象就是一個 XAConnection 對象的工廠。XAConnection s 是參與 JTA 事務的 JDBC 連接。” 要使用JTA事務,必須使用XADataSource來產生數據庫連接,產生的連接為一個XA連接。 XA連接(javax.sql.XAConnection)和非XA(java.sql.Connection)連接的區別在于:XA可以參與JTA的事務,而且不支持自動提交。 Note: Oracle,Sybase,DB2,SQL Server等大型數據庫才支持XA,支持分布事務。 My SQL 連本地都支持不好,更別說分布事務了。 MySql 在5.0的版本后增加了對xa的支持2實例
用XADataSource產生的XAConnection它擴展了一個getXAResource()方法,事務通過這個方法把它加入到事務容器中進行管理.對于調用者來說,根本看不到事務是如何管理的,你只要聲明開始事務,告訴容器我下面的操作要求事務參與了,最后告訴事務說到這兒可以提交或回滾了,別的都是暗箱操作。 首先,實現一個Xid類用來標識事務: 在使用JTA之前,你必須首先實現一個Xid類用來標識事務(在普通情況下這將由事務管理程序來處理)。Xid包含三個元素:formatID、gtrid(全局事務標識符)和bqual(分支修飾詞標識符)。 下面的例子說明Xid的實現: 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; } } 其次,創建數據源: 其次,你需要創建一個你要使用的數據庫的數據源: 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“這個例子是用“兩步提交協議”來提交一個事務分支: 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:這個例子說明一個分布式事務分支如何中止,讓相同的連接做本地事務處理,以及它們稍后該如何繼續這個分支。分布式事務的兩步提交作用不影響本地事務。 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); 這個更新在事務范圍之外完成,所以它不受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資源如何分擔不同的事務。創建了兩個事務分支,但是它們不屬于相同的分布式事務。JTA允許XA資源在第一個分支上做一個兩步提交,雖然這個資源仍然與第二個分支相關聯。 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:這個例子說明不同的連接上的事務分支如何連接成為一個單獨的分支,如果它們連接到相同的資源管理程序。這個特點改善了分布式事務的效率,因為它減少了兩步提交處理的數目。兩個連接到數據庫服務器上的XA將被創建。每個連接創建它自己的XA資源,正規的JDBC連接和語句。在第二個XA資源開始一個事務分支之前,它將察看是否使用和第一個XA資源使用的是同一個資源管理程序。如果這是實例,它將加入在第一個XA連接上創建的第一個分支,而不是創建一個新的分支。稍后,這個事務分支使用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:這個例子說明在錯誤恢復的階段,如何恢復準備好的或者快要完成的事務分支。它首先試圖返回每個分支;如果它失敗了,它嘗試著讓資源管理程序丟掉關于事務的消息。 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); } } } [摘自百度文庫]轉載于:https://www.cnblogs.com/kentyouyou/p/3468670.html
總結
以上是生活随笔為你收集整理的[JTA] Java事务api的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于visual Studio2013解
- 下一篇: 怎么中新股