Monday, November 12, 2007

Distributed Transactions::JAVA-JDBC3

Transaction Management

Participation in a distributed transaction is defined as the work done between invocations of the methods XAResource.start and XAResource.end. Outside these boundaries, the transaction mode is local, and a connection behaves exactly like a local connection. With one exception, there is no difference in how an application participating in a distributed transaction is coded. In contrast to the local case, the boundaries of a distributed transaction must be controlled by an external transaction manager that is coordinating the work of multiple connections. For this reason, it is an error for applications to call any of the following Connection methods while they are participating in a distributed transaction:

  • setAutoCommit(true)
  • commit
  • rollback
  • setSavepoint
The JDBC driver throws an SQLException if one of these operations is attempted on a connection that is participating in a distributed transaction. If the connection is later used for a local transaction, these operations are legal at that point. Applications should also refrain from calling Connection.setTransactionIsolation within the bounds of a distributed transaction. The resulting behavior is implementation-defined. If a connection has auto-commit mode already enabled at the time it joins a global transaction, the attribute will be ignored. The auto-commit behavior will resume when the connection returns to local transaction mode.

Two-phase Commit

The following steps outline how a transaction manager uses XAResource objects to implement the two-phase commit protocol. These steps assume a three-tier architecture where an application server is working with an external transaction manager:

1. The application server gets XAResource objects from two different connections:
// XAConA connects to resource manager A
javax.transaction.xa.XAResource resourceA = XAConA.getXAResource();

// XAConB connects to resource manager B
javax.transaction.xa.XAResource resourceB = XAConB.getXAResource();

CODE EXAMPLE Getting the XAResource object from an XAConnection object

2. The application server passes the XAResource objects to the transaction manager.
The transaction manager does not access the associated XAConnection objects
directly.
3. The transaction manager uses the XAResource objects to assign a piece of the
transaction to each of the associated resource managers. The transaction is
identified by xid, which represents the identifier generated by the transaction
manager when the transaction is created.

// Send work to resource manager A. The TMNOFLAGS argument indicates
// we are starting a new branch of the transaction, not joining or
// resuming an existing branch.
resourceA.start(xid, javax.transaction.xa.TMNOFLAGS);
// do work with resource manager A
...
// tell resource manager A that it’s done, and no errors have occurred
resourceA.end(xid, javax.transaction.xa.TMSUCCESS);
// do work with resource manager B.
resourceB.start(xid, javax.transaction.xa.TMNOFLAGS);
// B’s part of the distributed transaction
...
resourceB.end(xid, javax.transaction.xa.TMSUCCESS);
CODE EXAMPLE Starting and ending transaction branches using the XAResource interface
4. The transaction manager initiates the two-phase commit protocol by asking each participant to vote:

resourceA.prepare(xid);
resourceB.prepare(xid);

CODE EXAMPLE Initiating two-phase commit A participating resource manager can vote to roll back the transaction by throwing a javax.transaction.xa.XAException.

5. If both participants vote to commit, the transaction manager tells each one to commit its piece of the distributed transaction (the second parameter tells the resource manager not to use a one phase commit protocol on behalf of the xid):

resourceA.commit(xid, false);
resourceB.commit(xid, false);

CODE EXAMPLE Committing the distributed transaction

6. If either resource manager votes to roll back, the transaction manager tells each one to roll back its piece of the transaction:

resourceA.rollback(xid);
resourceB.rollback(xid);

CODE EXAMPLE Rolling back the distributed transaction The transaction manager is not required to use the same XAResource object to commit/rollback a transaction branch as was used to execute the branch. If different XAResource objects are used, however, they must be associated with XAConnection objects that connect to the same resource manager.
Note – Steps 1-6 also apply to the case where XAConA and XAConB are two physical
connections to the same resource manager.

Closing the Connection

In a typical distributed transaction environment, the middle-tier server needs to be notified when an application has finished using a connection. As in the earlier discussion of PooledConnection objects, the middle-tier server will add itself as a ConnectionEventListener so that it will be notified when the application calls the method Connection.close. At this point, the server will notify the transaction manager so that it can end the transaction branch for the corresponding XAResource object. If the server’s DataSource implementation includes connection pooling, the connection pooling module will be notified that it can return the physical XAConnection object to the pool.

Note – A distributed transaction may still be active after a participating Connection object is closed. This is not true for local transactions.

Limitations of the XAResource Interface

The javax.transaction.xa.XAResource interface is limited to defining only the set of methods needed to join and participate in global transactions, as defined by the X/Open XA standard. This allows any resource manager that implements the interface to participate with any other resource manager or transaction manager that has the same level of support. Functionality that is not defined in the X/Open standard is correspondingly not defined in the XAResource interface. Resource managers that provide for support of features not defined in the X/Open XA standard, such as setting isolation levels in global transactions, will have to do so in an implementation-defined way. Users who use implementation-defined features should be aware that they will limit the portability of their applications.

No comments: