Distributed transactions

Typically, transactions in Java™ Database Connectivity (JDBC) are local. This means that a single connection performs all the work of the transaction and that the connection can only work on one transaction at a time. When all the work for that transaction has been completed or has failed, commit or rollback is called to make the work permanent, and a new transaction can begin. There is, however, also advanced support for transactions available in Java that provides functionality beyond local transactions. This support is fully specified by the Java Transaction API.

The Java Transaction API (JTA) has support for complex transactions. It also provides support for decoupling transactions from Connection objects. As JDBC is modeled after the Object Database Connectivity (ODBC) and the X/Open Call Level Interface (CLI) specifications, JTA is modeled after the X/Open Extended Architecture (XA) specification. JTA and JDBC work together to decouple transactions from Connection objects. By decoupling transactions from Connection objects, this allows you to have a single connection work on multiple transactions concurrently. Conversely, it allows you to have multiple Connections work on a single transaction.

Java Transaction API (JTA) 1.0.1 specification

Note: If you are planning to work with JTA, refer to Get started with JDBC for more information about required Java Archive (JAR) files in your extensions classpath. You want both the JDBC 2.0 optional package and the JTA JAR files (these files are found automatically by the JDK if you are running JDK 1.4 or a subsequent version). These are not found by default.

Transactions with JTA

When JTA and JDBC are used together, there are a series of steps between them to accomplish transactional work. Support for XA is provided through the XADataSource class. This class contains support for setting up connection pooling exactly the same way as its ConnectionPoolDataSource superclass.

With an XADataSource instance, you can retrieve an XAConnection object. The XAConnection object serves as a container for both the JDBC Connection object and an XAResource object. The XAResource object is designed to handle XA transactional support. XAResource handles transactions through objects called transaction IDs (XIDs).

The XID is an interface that you must implement. It represents a Java mapping of the XID structure of the X/Open transaction identifier. This object contains three parts:

See the JTA specification for complete details on this interface.

Example: Use JTA to handle a transaction shows how to use JTA to handle a transaction in an application.

Use UDBXADataSource support for pooling and distributed transactions

The Java Transaction API support provides direct support for connection pooling. UDBXADataSource is an extension of a ConnectionPoolDataSource, allowing application access to pooled XAConnection objects. Since UDBXADataSource is a ConnectionPoolDataSource, the configuration and use of the UDBXADataSource is the same as that described in Use DataSource support for object pooling.

XADataSource properties

In addition to the properties provided by the ConnectionPoolDataSource, the XADataSource interface provides the following properties:

Set method (data type) Values Description
setLockTimeout (int) 0 or any positive value Any positive value is a valid lock timeout (in seconds) at the transaction level.

A lock timeout of 0 means that there is no lock timeout value enforced at the transaction level, although there may be one enforced at other levels (the job or the table).

The default value is 0.

setTransactionTimeout (int) 0 or any positive value Any positive value is a valid transaction timeout (in seconds).

A transaction timeout of 0 means that there is no transaction timeout value enforced. If the transaction is active for longer than the timeout value, it is marked rollback only, and subsequent attempts to perform work under it causes an exception to occur.

The default value is 0.

ResultSets and transactions

Besides demarcating the start and end of a transaction as shown in the previous example, transactions can be suspended for a time and resumed later. This provides a number of scenarios for ResultSet resources that are created during a transaction.

Simple transaction end

When you end a transaction, all open ResultSets that were created under that transaction automatically close. It is recommended that you explicitly close your ResultSets when you are finished using them to ensure maximum parallel processing. However, an exception results if any ResultSets that were opened during a transaction are accessed after the XAResource.end call is made.

See Example: End a transaction that shows this behavior.

Suspend and resume

While a transaction is suspended, access to a ResultSet created while the transaction was active is not allowed and results in an exception. However, once the transaction is resumed, the ResultSet is available again and remains in the same state it was in before the transaction was suspended.

See Example: Suspend and resume a transaction that shows this behavior.

Effecting suspended ResultSets

While a transaction is suspended, the ResultSet cannot be accessed. However, Statement objects can be reprocessed under another transaction to perform work. Because JDBC Statement objects can have only one ResultSet at a time (excluding the JDBC 3.0 support for multiple concurrent ResultSets from a stored procedure call), the ResultSet for the suspended transaction must be closed to fulfill the request of the new transaction. This is exactly what happens.

See Example: Suspended ResultSets that shows this behavior.

Note: Although JDBC 3.0 allows a Statement to have multiple ResultSets open simultaneously for a stored procedure call, they are treated as a single unit and all of them close if the Statement is reprocessed under a new transaction. It is not possible to have ResultSets from two transactions active simultaneously for a single statement.

Multiplexing

The JTA API is designed to decouple transactions from JDBC connections. This API allows you to have either multiple connections work on a single transaction or a single connection work on multiple transactions concurrently. This is called multiplexing and many complex tasks can be performed that cannot be accomplished with JDBC alone.

This example shows multiple connections working on a single transaction.

This example shows a single connection with multiple transactions taking place at once.

For further information on using JTA, see the JTA specification. The JDBC 3.0 specification also contains information on how these two technologies work together to support distributed transactions.

Two-phase commit and transaction logging

The JTA APIs externalize the responsibilities of the distributed two-phase commit protocol completely to the application. As the examples have shown, when using JTA and JDBC to access a database under a JTA transaction, the application uses the XAResource.prepare() and XAResource.commit() methods or just the XAResource.commit() method to commit the changes.

In addition, when accessing multiple distinct databases using a single transaction, it is the application's responsibility to ensure that the two-phase commit protocol and any associated logging required for transaction atomicity across those databases are performed. Typically, the two-phase commit processing across multiple databases (that is, XAResources) and its logging are performed under the control of an application server or transaction monitor so that the application itself does not actually concern itself with these issues.

For example, the application may call some commit() method or return from its processing with no errors. The underlying application server or transaction monitor would then begin processing for each database (XAResource) that participated in the single distributed transaction.

The application server would use extensive logging during the two-phase commit processing. It would call the XAResource.prepare() method in turn for each participant database (XAResource), followed by a call to the XAResource.commit() method for each participant database (XAResource).

If a failure occurs during this processing, the application server's transaction monitor logs allow the application server itself to subsequently use the JTA APIs to recover the distributed transaction. This recovery, under the control of the application server or transaction monitor, allows the application server to get the transaction to a known state at each participant database (XAResource). This ensures a well-known state of the entire distributed transaction across all participant databases.