4 Distributed Transaction Processing: JTA

This chapter describes the TimesTen implementation of the Java Transaction API (JTA).

The TimesTen implementation of the Java JTA interfaces is intended to enable Java applications, application servers, and transaction managers to use TimesTen resource managers in distributed transaction processing (DTP) environments. The TimesTen implementation is supported for use by the Oracle WebLogic Server.

The purpose of this chapter is to provide information specific to the TimesTen implementation of JTA and is intended to be used with the following documents:

As TimesTen JTA is built on top of the TimesTen implementation of the X/Open XA standard, much of the discussion here is in terms of underlying XA features. You can also refer to "Distributed Transaction Processing: XA" in Oracle TimesTen In-Memory Database C Developer's Guide.

This chapter includes the following topics:

Important:

  • The TimesTen XA implementation does not work with the TimesTen Application-Tier Database Cache (TimesTen Cache). The start of any XA transaction fails if the cache agent is running.

  • You cannot execute an XA transaction if replication is enabled.

  • Do not execute DDL statements within an XA transaction.

Overview of JTA

This section provides a brief overview of the following XA concepts.

X/Open DTP model

Figure 4-1 illustrates the interfaces defined by the X/Open DTP model.

Figure 4-1 Distributed transaction processing model

Description of Figure 4-1 follows
Description of "Figure 4-1 Distributed transaction processing model"

The TX interface is what applications use to communicate with a transaction manager. The figure shows an application communicating global transactions to the transaction manager. In the DTP model, the transaction manager breaks each global transaction down into multiple branches and distributes them to separate resource managers for service. It uses the JTA interface to coordinate each transaction branch with the appropriate resource manager.

In the context of TimesTen JTA, the resource managers can be a collection of TimesTen databases, or databases in combination with other commercial databases that support JTA.

Global transaction control provided by the TX and JTA interfaces is distinct from local transaction control provided by the native JDBC interface. It is generally best to maintain separate connections for local and global transactions. Applications can obtain a connection handle to a TimesTen resource manager to initiate both local and global transactions over the same connection.

Two-phase commit

In a JTA implementation, the transaction manager commits the distributed branches of a global transaction by using a two-phase commit protocol.

  1. In phase 1, the transaction manager directs each resource manager to prepare to commit, which is to verify and guarantee it can commit its respective branch of the global transaction. If a resource manager cannot commit its branch, the transaction manager rolls back the entire transaction in phase 2.

  2. In phase 2, the transaction manager either directs each resource manager to commit its branch or, if a resource manager reported it was unable to commit in phase 1, rolls back the global transaction.

Note the following optimizations.

  • If a global transaction is determined by the transaction manager to have involved only one branch, it skips phase 1 and commits the transaction in phase 2.

  • If a global transaction branch is read-only, where it does not generate any transaction log records, the transaction manager commits the branch in phase 1 and skips phase 2 for that branch.

Note:

The transaction manager considers the global transaction committed if and only if all branches successfully commit.

Using JTA in TimesTen

This section discusses the following considerations for using JTA in TimesTen:

TimesTen database requirements for XA

To guarantee global transaction consistency, TimesTen XA transaction branches must be durable. The TimesTen implementation of the xa_prepare(), xa_rollback(), and xa_commit() functions log their actions to disk, regardless of the value set in the DurableCommits general connection attribute or by the ttDurableCommit built-in procedure. If you must recover from a failure, both the resource manager and the TimesTen transaction manager have a consistent view of which transaction branches were active in a prepared state at the time of failure.

Global transaction recovery in TimesTen

When a database is loaded from disk to recover after a failure or unexpected termination, any global transactions that were prepared but not committed are left pending, or in doubt. Normal processing is not enabled until the disposition of all in-doubt transactions has been resolved.

After connection and recovery are complete, TimesTen checks for in-doubt transactions. If there are no in-doubt transactions, operation proceeds as normal. If there are in-doubt transactions, other connections may be created, but virtually all operations are prohibited on those connections until the in-doubt transactions are resolved. Any other JDBC calls result in the following error:

Error 11035 - "In-doubt transactions awaiting resolution in recovery must be 
resolved first"

The list of in-doubt transactions can be retrieved through the XA implementation of xa_recover(), then dealt with through the XA call xa_commit(), xa_rollback(), or xa_forget(), as appropriate. After all the in-doubt transactions are cleared, operations proceed normally.

This scheme should be adequate for systems that operate strictly under control of the transaction manager, since the first thing the transaction manager should do after connect is to call xa_recover().

If the transaction manager is unavailable or cannot resolve an in-doubt transaction, you can use the ttXactAdmin utility -HCommit or -HAbort option to independently commit or abort the individual transaction branches. Be aware, however, that these ttXactAdmin options require ADMIN privilege. See "ttXactAdmin" in Oracle TimesTen In-Memory Database Reference.

XA error handling in TimesTen

The XA specification has a limited, strictly defined set of errors that can be returned from XA interface calls. The ODBC SQLError mechanism returns XA defined errors, along with any additional information.

The TimesTen XA related errors begin at number 11000. Errors 11002 through 11020 correspond to the errors defined by the XA standard.

See "Warnings and Errors" in Oracle TimesTen In-Memory Database Error Messages and SNMP Traps for the complete list of errors.

Using the JTA API

The TimesTen implementation of JTA provides an API consistent with that specified in the JTA specification. TimesTen JTA operates on JDK 1.4 and above.

This section covers the following topics for using the JTA API:

Regarding how to register a TimesTen DSN with WebLogic, information on configuring TimesTen for application servers and object-relational mapping frameworks is available in the TimesTen Quick Start. Click Java EE and OR Mapping under Configuration and Setup.

Required packages

The TimesTen JDBC and XA implementations are available in the following packages:

com.timesten.jdbc.*;
com.timesten.jdbc.xa.*;

Your application should also import these standard packages:

import java.sql.*;
import javax.sql.*;
import javax.transaction.xa.*;

Creating a TimesTen XAConnection object

Connections to XA data sources are established through XADataSource objects. You can create an XAConnection object for your database by using the TimesTenXADataSource instance as a connection factory. TimesTenXADataSource implements the javax.sql.XADataSource interface.

After creating a new TimesTenXADataSource instance, use the setUrl() method to specify a database.

The URL should look similar to the following.

  • For a direct connection: jdbc:timesten:direct:DSNname

  • For a client connection: jdbc:timesten:client:DSNname

You can also optionally use the setUser() and setPassword() methods to set the ID and password for a specific user.

Note:

Privilege must be granted to connect to a database. Refer to "Access control for connections".

Example 4-1 Creating a TimesTen XA data source object

In this example, the TimesTenXADataSource object is used as a factory to create a new TimesTen XA data source object. Then the URL that identifies the TimesTen DSN (dsn1), the user name (myName), and the password (myPasswd) are set for this TimesTenXADataSource instance. Then the getXAConnection() method is used to return a connection to the object, xaConn.

TimesTenXADataSource xads = new TimesTenXADataSource();
 
xads.setUrl("jdbc:timesten:direct:dsn1");
xads.setUser("myName");
xads.setPassword("myPassword");
 
XAConnection xaConn = null;
try {
    xaConn = xads.getXAConnection();
}
catch (SQLException e){
    e.printStackTrace();
    return;
}

You can create multiple connections to an XA data source object. This example creates a second connection, xaConn2:

XAConnection xaConn  = null;
XAConnection xaConn2 = null;

try {
    xaConn  = xads.getXAConnection();
    xaConn2 = xads.getXAConnection();
}

Example 4-2 Creating multiple TimesTen XA data source objects

This example creates two instances of TimesTenXADataSource for the databases named dsn1 and dsn2. It then creates a connection for dsn1 and two connections for dsn2.

TimesTenXADataSource xads = new TimesTenXADataSource();
 
xads.setUrl("jdbc:timesten:direct:dsn1");
xads.setUser("myName");
xads.setPassword("myPassword");
 
XAConnection xaConn1 = null;
XAConnection xaConn2 = null;
XAConnection xaConn3 = null;
 
try {
   xaConn1 = xads.getXAConnection(); // connect to dsn1
}
catch (SQLException e){
   e.printStackTrace();
   return;
}
 
xads.setUrl("jdbc:timesten:direct:dsn2");
xads.setUser("myName");
xads.setPassword("myPassword");
 
try {
   xaConn2 = xads.getXAConnection(); // connect to dsn2
   xaConn3 = xads.getXAConnection(); // connect to dsn2
}
catch (SQLException e){
   e.printStackTrace();
   return;
}

Note:

Once an XAConnection is established, autocommit is turned off.

Creating XAResource and Connection objects

After using getXAConnection() to obtain an XAConnection object, you can use the XAConnection method getXAResource() to obtain an XAResource object, then the XAConnection method getConnection() to obtain a Connection object for the underlying connection.

Example 4-3 Getting an XA resource object and a connection

//get an XAResource
XAResource xaRes = null;
try {
   xaRes = xaConn.getXAResource();
}
catch (SQLException e){
   e.printStackTrace();
   return;
}
 
//get an underlying physical Connection
Connection conn = null;
try {
   conn = xaConn.getConnection();
}
catch (SQLException e){
   e.printStackTrace();
   return;
}

From this point, you can use the same connection, conn, for both local and global transactions. Be aware of the following, however.

  • You must commit or roll back an active local transaction before starting a global transaction. Otherwise you get the XAException exception XAER_OUTSIDE.

  • You must end an active global transaction before initiating a local transaction, otherwise you get a SQLException, "Illegal combination of local transaction and global (XA) transaction."