J2EE Transaction Frameworks: Distributed Transaction Primer

In the first part of this series, we covered the basics of
transaction processing in a distributed component based system. In
this part, the two main types of transactions possible in a J2EE
configuration are described. Issues of isolation and serialization of
resource managers are discussed. Explicit transaction management using
JTA API for the three typical J2EE configurations is described in
detail.

Transactions in J2EE configurations

In Part 1 of this
series we ended the discussion identifying the three common J2EE
configurations found in applications. For the benefit of the reader,
the figure showing those configurations is repeated below.

This part will explain how the different types of transaction types
map to the cases mentioned above.

J2EE transaction types

The typical configuration of a J2EE application is an application
component deployed in a container provided by an application
server. The application component needs transactional access to
multiple resource managers and uses a transaction manager that's
responsibile for managing transactions across multiple resource
managers.

Figure 2. Participating components in a J2EE transaction

A resource manager as shown in the figure above can support two
types of transactions:

JTA/XA Transaction: The transaction manager that
controls and coordinates the transaction is external to the resource
manager. Such a transaction is henceforth referred to as a JTA or an
XA transaction.

RM/Local Transaction: The transaction manager that controls
and coordinates the transaction is internal to the resource manager
The coordination of such transactions involves no external transaction
managers. This means the Transaction Manager component shown in the
figure above is part of the Resource Manager.

A transaction manager as shown above (1) coordinates transactions
across multiple resource managers and (2) provides additional low
level services to propagate transactional context across multiple
resource managers. The J2EE connector architecture defines a
transaction management contract between an application server
and a resource adapter with its underlying resource manager. The
transaction management contract has two parts, depending on the type
of transaction:

a JTA javax.transaction.xa.XAResource based
contract between a transaction manager and a resource manager

a local transaction management contract

An application server vendor uses this to provide the
infrastructure and runtime environment for transaction
management. Application components in turn rely on this transaction
infrastructure to support their component level transaction model.

Note: It is important to emphasize that most enterprise
information systems support some form of transaction management. For
example, a typical JDBC database allows multiple SQL updates to be
grouped in an atomic transaction. Components should always access any
resource (database or an enterprise information system) under the
scope of a transaction since this provides some guarantee on the
integrity and consistency of underlying data being accessed. Such
systems can be accessed under either a JTA transaction or a resource
manager (RM) local transaction.

In the following figure, a client invokes a method on the remote
interface of an EJB A. EJB A accesses resources managed by an EIS A
and calls EJB Y to access another EIS B.

Figure 3. Transactions across multiple Resource Managers.

The application server uses a transaction manager to enable an
application component to perform transactional access across multiple
EIS resource managers. The transaction manager manages transactions
across multiple resource managers and supports propagation of the
transaction context across distributed systems. The transaction
manager supports a JTA XAResource transaction management
contract with a resource manager. The EIS system A supports JTA
transactions by implementing a XAResource interface
through its resource manager. The EIS system B also implements the
XAResource interface. This interface enables the two
resource managers to participate in transactions that are coordinated
by an external transaction manager. The XAResource
interface is used by the transaction manager to manage transactions
across the two underlying resource managers. As the EJBs A and B
access the EIS systems, the application server enlists the connections
to both the systems from their respective resource managers. Finally
when the transaction commits, the transaction manager performs a 2PC
protocol across the two resource managers, ensuring that all read and
write access to resources managed by both the EIS systems is either
entirely committed or entirely rolled back.

Currently, the J2EE platform is only required to support access to
a single JDBC database within a transaction (multiple connections to
the same database are allowed). It is not required to support access
to multiple JDBC databases within a single transaction. It is also not
required to support access to other types of enterprise information
systems such as enterprise resource planning systems. However, some
products might choose to provide these extra transactional
capabilities. For example, the J2EE SDK supports access to multiple
JDBC databases in one transaction using the two-phase commit
protocol. It is important for developers to understand and distinguish
which transaction capabilities are required and which are optional in
a J2EE product. For true portability of an application, only features
required by the J2EE specification should be used. For example, if a
J2EE application needs to access multiple databases under a single
transaction, it will not run properly on a J2EE product that does not
support two-phase commit.

Figure 4. J2EE transaction types and its components.

The figure shown above illustrates the different types of
transaction management and their associated components. It is meant to
clarify the relationships between JTA transaction, the EJBs and their
bean managed or container managed demarcation. Note that it is always
possible to do explicit local transactions from fat clients, servlets
or EJBs provided the resource manager offers some transactional
API.

Serialization and isolation levels

An isolation level defines how concurrent transactions
accessing a RDBMS or an EIS are isolated from one another for read
purposes. The following the isolation levels are generally supported
in any RDBMS or EIS. These levels are defined in the ANSI SQL92
standard in terms of three phenomena that must be prevented between
concurrent transactions.

Dirty reads: A transaction reads a row in a database table containing uncommitted changes from another transaction.

Nonrepeatable reads: A transaction reads a row in a database table, a second transaction changes the same row and the first transaction rereads the row and gets a different value.

Phantom reads: A transaction re-executes a query, returning a set of rows that satisfies a search condition and finds that another committed transaction has inserted additional rows that satisfy the condition.

Following are the descriptions of the isolation levels.

TRANSACTION_READ_UNCOMMITTED: The transaction can read uncommitted data, i.e., data being changed by another transaction concurrently.

TRANSACTION_READ_COMMITTED: This level results in the prevention of a transaction from reading uncommitted changes in other concurrent transactions. This level ensures that dirty reads are not possible.

TRANSACTION_REPEATABLE_READ: In addition to the prevention associated with TRANSACTION_READ_COMMITTED, this level ensures that reading the same data multiple times will receive the same value even if another transaction modifies the data. Methods with this isolation level, besides having the same behavior as TRANSACTION_READ_COMMITTED, can only execute repeatable reads.

TRANSACTION_SERIALIZABLE: The transaction has exclusive read and update privileges to data by locking it; other transactions can neither write nor read the same data. It is the most restrictive transaction isolation level and it ensures that if a query retrieves a result set based on a predicate condition and another transaction inserts data that satisfy the predicate condition, re-execution of the query will return the same result set.

Isolation level summary

Isolation Level

Dirty Read

Non Repeatable Read

Phantom Read

TRANSACTION_READ_UNCOMMITTED

YES

YES

YES

TRANSACTION_READ_COMMITTED

NO

YES

YES

TRANSACTION_REPEATABLE_READ

NO

NO

YES

TRANSACTION_SERIALIZABLE

NO

NO

NO

The table shown above summarizes the discussion. A lower level of
isolation allows greater concurrency at the expense of more
complicated logic to deal with potential data inconsistencies. A
useful guideline is to use the highest isolation level provided by the
RDBMS or the EIS that gives acceptable performance. Although the
TX_SERIALIZABLE attribute guarantees the highest level of data
integrity, it is offset by a performance trade-off because even simple
reads must wait in line. All RDBMS or EIS used by a J2EE
application should use the same isolation level for consistency
reasons since the current J2EE specification does not define a
standard way to set isolation levels when an EIS is accessed via JTA
transactions. If a J2EE product does not provide a way to configure
the isolation level, the RDBMS or EIS will use a default isolation
level, which for most of the relational databases is
TRANSACTION_READ_COMMITTED. It is strongly recommended not to change
the isolation level within a transaction, especially if some work has
already been done. Some enterprise information systems may even force
a commit if it is attempted to change the isolation level in the
middle of a transaction. They're mapped in JDBC to the static
variables defined in the java.sql.Connection interface.

JTA/XA Transactions

A transaction managed and coordinated by the J2EE platform is a JTA
or XA transaction. A J2EE product is required to support JTA
transactions according to the transaction requirements defined in the
J2EE specification. There are two ways to begin a JTA transaction. A
component can begin a JTA transaction explicitly using the JTA
javax.transaction.UserTransaction interface or it can
also be started implicitly or automatically by the EJB container if an
EJB bean uses container managed transaction specification. The main
benefit of using JTA transactions is the ability to seamlessly combine
multiple application components and RDBMS/EIS accesses into one single
transaction with a little coding effort. For example, if a component X
begins a JTA transaction and invokes a method of component Y, the
transaction will be propagated transparently from component X to Y by
the platform. Enterprise beans using container-managed transaction
demarcation will not need to begin or commit transactions
programmatically as the demarcation is handled automatically by the
EJB container itself. It is always recommended to access an RDBMS or
EIS within the scope of a JTA transaction. JTA allows applications to
access transaction management independent of any specific
implementation by specifying standard Java interfaces between a
transaction manager, the transactional application, the J2EE server,
and the resource managers.

OMG Object Transaction Service JTS specifies the
implementation of a transaction manager that supports JTA and
implements the Java mapping of the OMG Object Transaction Service
(OTS) 1.1 specification. JTS propagates transactions using IIOP. A JTS
transaction manager provides the services and management functions
required to support transaction demarcation, transactional resource
management, synchronization, and transaction context propagation. An
application component developer uses the JTA
UserTransaction interface to demarcate JTA transaction
boundaries in components. The JTS TransactionManager and
XAResource interfaces are low level APIs between a J2EE
server and enterprise information system resource managers and are not
intended to be used by applications. A J2EE platform might choose to
use a JTS implementation to support the transaction semantics defined
in J2EE specification. An example is the J2EE SDK. The JTS
implementation is transparent to J2EE components. Components should
never interact directly with JTS. Instead, they should use the JTA
UserTransaction interface for transaction
demarcation.

Transactions in clients: Case I

This is the case where the J2EE configuration is {Stand-alone
Client <-> EJB Container <-> RDBMS/EIS
Resources}. Transaction support in applets and application clients is
not required by the J2EE platform. However, a J2EE product might
choose to implement and provide this capability for added value. So
the ability of applets and fat standalone application clients to
directly access a UserTransaction object depends entirely on the
capabilities provided by the container. To ensure portability, applets
and application clients should delegate transactional work to the
lower tier of enterprise beans.

Transactions in web components: Case II

This is the case where the J2EE configuration is {Browser <->
Web Container <-> RDBMS/EIS Resources}. It is possible for a
servlet or a JSP page to use JNDI lookup to get hold of a
UserTransaction object and use the underlying interface
to programmatically specify transactions. In a two-tier application
configuration where a web component needs to access enterprise
information systems under the scope of a JTA transaction, this is
quite common. The code snippet below illustrates the use of the JTA
interface to specify transactions within a web component:

It is important to keep in mind that a web component like a servlet
may only start a transaction in its service
method. Moreover, a transaction started by a servlet or a JSP page
must be completed before the service method returns. Transactions
cannot span across web requests. The following guidelines are
recommended for handling interactions in web components between JTA
transactions, threads, and JDBC connections.

JTA transactions should start and complete only from the
thread in which the service method is called. Additional threads
created in the servlet should not attempt to start any JTA
transaction.

JDBC connections may be acquired and released by a thread other
than the service method thread, but should not be shared between
threads.

JDBC Connection objects should not be stored in static fields.

For web components implementing the SingleThreadModel, JDBC Connection objects may be stored in class instance fields.

For web components (servlets) not implementing the
SingleThreadModel, JDBC Connection objects
should not be stored in class instance fields and should be acquired
and released within the same invocation of the service
method.

Transactions in application servers: Case III

This is the case where the J2EE configuration is {Browser <->
Web Container <-> EJB Container <-> RDBMS/EIS
Resources}. The following scenarios are illustrated to motivate
discussions on use of transactions in application servers with EJB
container and a built in transaction monitor.

It's possible for an application using EJB servers to send messages
to or receive messages from one or more JMS destinations or update
data in one or more databases in a single transaction. In the
following figure, a client invokes a method on the remote interface of
enterprise Bean A. which in turn sends a message to a JMS queue and
updates data in a database A. After that, EJB A calls a method of
another enterprise Bean B that updates data in database B. The
application server with its EJB container and built in transaction
manager ensures that the operations on A, B, and C are either all
committed or rolled back.

Figure 5. Message sent to JMS queue and updates to multiple databases

The application programmer does not have to do anything to ensure
transactional semantics. The EJBs A and B perform the sending of the
message and database updates using the standard JMS and JDBC
APIs. Behind the scenes, the application server enlists the session on
the connection to the JMS provider and the database connections as
part of the transaction. When the transaction commits, the application
server and the messaging and database systems perform a two-phase
commit protocol to ensure atomic updates across all the three
resources.

The J2EE architecture allows updates of data at multiple sites to
be performed in a single transaction. In the following figure, a
client invokes a method on enterprise Bean A. which in turn sends a
message to a message queue, updates data in database A. After that,
EJB A calls a method in another EJB B deployed in another application
server which updates data in database B. The EJB architecture makes it
possible to perform the updates to databases A and B in a single
transaction.

Figure 6. Updates to multiple databases in same transaction

When EJB A invokes EJB B, the two application servers cooperate to
propagate the transaction context from A to B. This transaction
context propagation is transparent to the application. At commit time,
the two application servers use distributed two phase commit protocol
(if the capability exists) to ensure the atomicity of the database
updates and the transaction.

The two types of transaction demarcation in enterprise beans,
namely, bean managed and container managed, are discussed in detail
next.

Bean managed transaction

As mentioned before, in a bean-managed transaction, an enterprise
bean uses the javax.transaction.UserTransaction interface
to explicitly specify transaction boundaries in the application
code. Only session beans and message driven beans can choose to use
bean-managed demarcation. An entity bean must always use container
managed transaction demarcation. The following code illustrates the
use of JTA interface to specify transactions in an enterprise bean
with bean-managed transaction demarcation.

t is possible for an enterprise bean to open and close a database
connection in each business method rather than hold the connection
open until the end of transaction. If the client in the following
example executes the sequence of methods {method1,
method2, method2, method3}, all
the database updates done by the multiple invocations of
method2 are performed in the scope of the same
transaction. This is the transaction started in method1
and committed in method3.

An enterprise bean with bean-managed transaction specification
need not and should not use the getRollbackOnly() and
setRollbackOnly()methods of the EJBContext interface
since, if necessary, it can obtain the status of a transaction by
using the getStatus() method of the
javax.transaction.UserTransaction interface. It can also
roll back a transaction using the rollback()method of the same
interface if required.

Bean Managed transaction for Message Driven Beans

There is never a client transaction context available when a
message driven bean is invoked because a distributed transaction
context does not flow with a JMS message. When a message driven bean
using bean managed transaction uses the
javax.transaction. UserTransaction interface
to specify transactions, the message receipt that causes the
onMessage() method of the bean to be invoked is not part
of the transaction. Container managed transaction with the
Required transaction attribute must be used if receipt of
a message is to be part of a transaction. A message driven bean's
newInstance, setMessageDrivenContext,
ejbCreate, and ejbRemove methods are called
with an unspecified transaction context.

Dibyendu Baksi
is a J2EE transactions systems and frameworks designer and developer for Sun Microsystems, Inc.