Java Transaction API Overview 2003-04-15 · Hefei Xiaoyu ·· Yesky Previous 1 2 3 JDBC Drivers and XARESOURCE To simplify XAResource instructions, these examples illustrate an application not containing application servers and item management programs How should I use JTA? Basically, the applications in these examples also serve as the task of application servers and matters. Most companies use transaction management programs and application servers because they can manage distributed transactions more efficiently than an application. However, follow these examples, an application developer can test the robustness of JTA support in the JDBC driver. And some examples may not work on a particular database because some internal problems associated on the database. Before using JTA, you must first implement an XID class to identify a transaction (which will be processed by the transaction manager in normal case). The XID contains three elements: formatid, gtrid (global transaction identifier), and BQUAL (branch modifier word identifier). Formatid is usually zero, which means you will be named using OSI CCR (Open Systems Interconnection Commitment, Concurrence, and Recovery). If you use another format, then the formatid should be greater than zero. The -1 value means XID is invalid. Gtrid and BQUAL can contain 64 byte binary codes to identify global transactions and branch transactions, respectively. The only requirement is that gtrid and bqua must be a global unique. In addition, this can be done by using the naming rules specification specified in the OSI CCR. The following example shows the implementation of the 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;}} Second, you need to create a data source you want to use:
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;} Example 1 - This example is to submit a transaction branch with "two-step submission protocol":
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, XIAResource. TMNOFLAGS); Stmt.executeUpdate ("INSERT INTO TEST_TABLE VALUES); 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 ();} Because all of these examples in initialization The code is the same or very similar, just some of the important part of the code from different. Example 2 - This example, similar to example 1, illustrates a return process: XARES.START (XID, XARESOURCE.TMNOFLLAGS); "Insert INTO TEST_TABLE VALUES); XARES.End (XID, XareSource) .Tmsuccess); RET = XARES.PREPARE (XID); if (Ret == XAResource.xa_ok) {xares.rollback (xid);} Example 3 - This example shows how a distributed transaction branch is aborted, so that the same connection is Local transaction processing, and how they will continue this branch later. Two-step submission of distributed transactions do not affect local affairs.
XID = new myxid (100, new byte [] {0x01}, new byte [] {0x02}); XARES.START (XID, XARESOURCE.TMNOFLLAGS); Stmt.executeUpdate ("INSERT INTO TEST_TABLE VALUES (100)"); XARES.END (XID, XARESOURCE.TMSUSPEND); ∥ This update is done outside of the transaction range, so it is not affected by the XA returns. 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);} Example 4 - This example shows how an XA resource shares different transactions. Two transaction branches have been created, but they do not belong to the same distributed transaction. JTA allows XA resources to make a two-step submission on the first branch, although this resource is still associated with the second branch. XID1 = new myxid (100, new byte [] {0x01}, new byte [] = new myxid (100, new byte [] {0x11}, new byte [] {0x22}); xares. Start (XID1, XARESOURCE.TMNOFLLAGS); "INSERT INTO TEST_TABLE1 VALUES (" INSERT INTO TEST_TABLE1 VALUES); XARES.END (XID1, XARESOURCE.TMSUCCESS; XARES.START (XID2, XARESOURCE.TMNOFLLAGS); RET = XARES. Prepare (XID1); if (RET == XARESOURCE.XA_OK) {xares.commit (xid2, false);} stmt.executeUpdate ("INSERT INTO TEST_TABLE2 VALUES); XARES.END (XID2, XARESOURCE.TMSUCCESS) RET = XARES.PREPARE (XID2); if (RET == XARESOURCE.XA_OK) {XARES. ROLLBACK (XID2);} Example 5 - This example shows how different connection transaction branches are connected to a separate branch, if They are connected to the same resource management program. This feature improves the efficiency of distributed transactions because it reduces the number of two-step submission processes. Two XA connecting to the database server will be created. Each connection creates its own XA resource, a regular JDBC connection, and statement. Before the second XA resource starts a transaction branch, it will look at whether to use and the first XA resource is the same resource manager. If this is an example, it will join the first branch created on the first XA connection instead of creating a new branch. Later, this transaction branch uses XA resources to prepare and submit.
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); 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); "INSERT INTO TEST_TABLE2 VALUES (" INSERT INTO TEST_TABLE2 VALUES); XARES2.END (XID1, XARESOURCE.TMSUCCESUCCESS);} else {xid2 = new myxid 100, new byte [] {0x01}, new byte [] {0x03}); XARES2.Start (XID2, XARESOURCE.TMNOFLAGS); Stmt2.executeUpdate ("INSERT INTO TEST_TABLE2 VALUES); XARES2.END (XID2) , XAResource.tmsus; RET = XARES2.PREPARE (XID2); if (Ret == XareSource.xa_ok) {xares2.co Mmit (XID2, FALSE);}} RET = XARES1.PREPARE (XID1); if (Ret == XARESOURCE.XA_OK) {XARES1.COMMIT (XID1, FALSE);} Example 6 - This example illustrates the stage of error recovery, How to recover or have a transaction branch to be completed. It first tried to return to each branch; if it fails, it tried to let the resource manager throw away the message about the transaction. MYXID [] XIDs; XIDS = XARES.Recover (XARESOURCE.TMSTARTRSCAN | XARESOURCE.TMENDRSCAN); for (int i = 0; xids! = Null&&
Try {
XARES. ROLLBACK (XIDS [I]);
}
Catch (XaException EX) {
Try {
XARES.FORGET (XIDS [I]);
}
Catch (XaException EX1) {
System.out.println ("Rollback / Forget Failed:" EX1.ErrorCode);
}
}
}