複製鏈接
請複製以下鏈接發送給好友

jta

鎖定
JTA,即Java Transaction API,JTA允許應用程序執行分佈式事務處理——在兩個或多個網絡計算機資源上訪問並且更新數據。JDBC驅動程序的JTA支持極大地增強了數據訪問能力。
中文名
JAVA事務API
外文名
Java Transaction API
所屬學科
計算機科學
簡    稱
jta
應用領域
計算機

jta基本信息

jtaJTA和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)承擔着所有事務參與單元者的相互通訊的責任。

jtaJTA與JDBC

JTA事務比JDBC事務更強大。一個JTA事務可以有多個參與者,而一個JDBC事務則被限定在一個單一的數據庫連接。下列任一個Java平台的組件都可以參與到一個JTA事務中:JDBC連接、JDO PersistenceManager 對象、JMS 隊列、JMS 主題、企業JavaBeans(EJB)、一個用J2EE Connector Architecture 規範編譯的資源分配器

jta劃分

要用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();
// ...
當應用程序調用commit()時,事務管理器使用兩段提交協議來結束事務。
JTA事務控制的方法:
.javax.transaction.UserTransaction接口提供

jta使用

應用程序調用begin()來起動事務,即可調用commit()也可以調用rollback()來結束事務。
開發人員經常使用JDBC來作為DAO類中的底層數據操作。
如果計劃使用JTA來劃分事務,你將需要一個實現了javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驅動。
實現了這些接口的驅動將有能力參與到JTA事務中。
一個XADataSource對象是一個XAConnection對象的工廠。XAConnections是參與到JTA事務中的連接。你需要使用應用程序服務器管理工具來建立XADataSource對象。

jta特殊指令

對於特殊的指令請參考應用程序服務器文檔和JDBC驅動文檔。
J2EE應用程序使用JNDI來查找數據源。
一旦應用程序有了一個數據源對象的引用,這會調用javax.sql.DataSource.getConnection()來獲得數據庫的連接。

jta連接

XA連接區別於非XA連接。要記住的是XA連接是一個JTA事務中的參與者。這就意味着XA連接不支持JDBC的自動提交特性。也就是説應用程序不必在XA連接上調用java.sql.Connection.commit()或java.sql.Connection.rollback()。相反,應用程序應該使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().

jtaDAO類總結

我們已經討論了JDBC和JTA是怎樣劃分事務的。每一種方法都有它的優點,因此你需要決定為你的應用程序選擇一個最適應的方法。在我們團隊許多最近的對於事務劃分的項目中使用JDBC API來創建DAO類。
這DAO類總結如下:
⒈事務劃分代碼被嵌入到DAO類內部
⒉DAO類使用JDBC API來進行事務劃分
⒊調用者沒有劃分事務的方法
⒋事務範圍被限定在一個單一的JDBC連接

jta應用程序

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注意

讓我們來關注下面的話:
“用 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的支持

jta實例

用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);
}
}
}