This Tech Tip reprinted with permission by

A transaction is a series of operations that must be performed atomically. In other words, each operation in the series must succeed for the entire transaction to be successful. If any operation in the transaction does not succeed, the entire transaction fails. At that point, any operations which have succeeded must be "rolled back" so that the end state matches what was in place before the transaction started.

For example, let's say you want to transfer $50 from a savings account (account number: 12345-1) to a checking account (account number 12345-2). The steps in this transaction can be stated in "pseudo code" as follows:


To run the transaction, the following code is required:


Let's assume that there are sufficient funds to subtract $50 from the savings account, so the first part of the transaction succeeds. However, let's also assume that the second part fails. When the computer attempts to add 50 dollars to the checking account, it discovers that the checking account is frozen. Because the second part of the transaction fails, the entire transaction fails. As a result, the first part of the transaction needs to be rolled back: $50 needs to be placed back into the savings account 12345-1. This is essential. Otherwise, each time the computer tries to transfer money from the savings to the checking account, it will lose the money!

If the entire transaction succeeds, then the entire transaction is committed, and the results are made permanent.

Note that the commit process takes two phases to complete. In the first phase, checks are made to see that the transaction ran without error. If there were no errors, the results are committed in the second phase. If there were errors in the first-phase check, the transaction is rolled back. This common transaction strategy is appropriately called the two-phase commit protocol.

Transactions in the J2EE Environment

There are typically three participants in a transaction: an application that initiates the request for the transaction, a data store (such as a database) that the transaction runs against, and an API (such as a driver) that communicates between the application and the data store. In the J2EE platform, the API (or driver) is provided by the J2EE-compliant application server. The application program calls the application server to perform the transaction.


The Java Transaction API (JTA) is part of the J2EE platform. The API gives you the ability to perform distributed transactions, that is, an application can use the API to perform transactions on more than one data store in the network at the same time. But to do this efficiently, it helps to have another component operating in the application server: a J2EE transaction manager. A transaction manager helps to efficiently schedule and execute the potentially large number of transactions coming in through the application server.


Many database vendors provide their own transaction managers. However, a particular DBMS's transaction manager might not work with databases from different vendors. If you want to work with these heterogeneous databases, for example, if you want to update multiple databases from different vendors, you should consider using a JTA transaction with a corresponding J2EE transaction manager. The JTA specification states that "A JTA transaction is controlled by the J2EE transaction manager." Note that the J2EE transaction manager does have one limitation: the J2EE transaction model is flat. Support for nested transactions is not part of J2EE. This means that the J2EE transaction manager cannot start a transaction for an instance until the previous transaction has ended.

A J2EE-conforming application server implements a transaction manager using the Java Transaction Service (JTS). The JTA provides the API to call into the lower-level JTS routines. Be sure not to confuse the JTA with the JTS.

Learning the JTA

There are three separate interfaces that you can use with the JTA to perform transactions, and each uses a unique approach to handling transactions. The interfaces are:

Because most J2EE programmers only use the first interface, the remainder of this tip focuses on that interface.

EJB Transactions: Container and Bean-Managed Transactions

In the J2EE environment, the most logical place to perform transactions is inside of an Enterprise JavaBeans (EJB) technology component (also called an enterprise bean). There are two approaches you can take if you use enterprise beans to perform transactions, The first approach allows the EJB container to manage the transaction boundaries. This puts less of a burden on the programmer. This approach is called container-managed transactions. The second approach allows the programmer more freedom by explicitly defining the boundaries of transactions in the enterprise bean code. This approach is called bean-managed transactions.

Container-managed transactions can be used with any type of enterprise bean (session bean, entity bean, or message-driven bean). With container-managed transactions, the EJB container sets the boundaries of the transaction. This is typically done by marking one or more methods in the bean as individual transactions. The container sets the transaction boundary just before the beginning of the method, and sets the end boundary just before the method exits. However, with container-managed transactions, each method can be only one transaction -- multiple transactions are not allowed. When deploying a bean, you specify which of the bean's methods are associated with transactions. You do this by setting the transaction attributes.

Transaction attributes control the scope of a transaction when one enterprise bean method calls another enterprise bean method. The JTA specification states that an enterprise bean method can be marked with one of six different transaction attributes in the EJB deployment descriptor. The transaction attribute indicates how the EJB container should treat the method called by the client enterprise bean when transactions are involved.

Transaction attributes appear in the EJB deployment descriptor as follows:


Here is what the specification says about each of the six transaction attributes:

There are two ways to roll back a container-managed transaction. If a system exception is thrown, the container automatically rolls back the transaction. You can also roll back a transaction by invoking the setRollbackOnly() method of the EJBContext interface. This instructs the container to roll back the transaction. If an enterprise bean throws an application exception, the rollback is not automatic, but the rollback can be initiated by a call to setRollbackOnly(). Note that you cannot invoke some JTA methods while using container-managed transactions. That's because these methods are reserved for use with bean-managed transactions. These methods are:

In a bean-managed transaction, the code in the session or message-driven bean explicitly marks the boundaries of the transaction. An entity bean cannot have bean-managed transactions, it must use container-managed transactions. When you code a bean-managed transaction for session or message-driven beans, you typically can use either JDBC or JTA transactions. A JDBC transaction is controlled by the transaction manager of the database management system, and not by the J2EE transaction manager. To perform a JDBC transaction, use the commit() and rollback() methods of the java.sql.Connection interface. The beginning of a transaction is generally assumed with the first SQL statement that follows the most recent commit(), rollback(), or connect() statement. For JTA transactions, you can invoke the begin(), commit(), and rollback() methods of the javax.transaction.UserTransaction interface. The begin() and commit() methods mark the transaction boundaries. If the transaction operations fail, an exception handler typically invokes the rollback() method, and throws an EJBException. The following code shows how to use the JTA javax.transaction.UserTransaction interface to perform a bean-managed transaction:

      UserTransaction ut = context.getUserTransaction();

try {
// Do whatever transaction functionality is necessary
} catch (Exception ex) {
try {
} catch (SystemException syex) {
throw new EJBException
("Rollback failed: " + syex.getMessage());
throw new EJBException
("Transaction failed: " + ex.getMessage());

The code to perform a JDBC bean-managed transaction is similar. Note, however, that the code turns off the auto-commit on the database connection. This way, the database treats all subsequent operations as a single transaction (until the code calls the commit() method) .

   try {            
Connection con = makeDatabaseConnection();
// Do whatever database transaction functionality
// is necessary
} catch (Exception ex) {
try {
} catch (SQLException sqx) {
throw new EJBException("Rollback failed: " +
} finally {

Here are a few rules stated by the JTA specification:

In a stateless session bean with bean-managed transactions, a business method must commit or roll back a transaction before returning. However, a stateful session bean does not have this restriction. In a stateful session bean with a JTA transaction, the association between the bean instance and the transaction is retained across multiple client calls. Even if each business method called by the client opens and closes the database connection, the association is retained until the instance completes the transaction. In a stateful session bean with a JDBC transaction, the JDBC connection retains the association between the bean instance and the transaction across multiple calls. If the connection is closed, the association is not retained.

There is one method limitation with JTA bean-managed transactions: do not invoke the getRollbackOnly() and setRollbackOnly() methods of the EJBContext interface (these methods should be used only in container-managed transactions). For bean-managed transactions, invoke the getStatus() and rollback() methods of the UserTransaction interface instead. And, be sure not to invoke any resource-specific functions that conflict with the transactional semantics.

For more information about JTA and JTS, see the J2EE Transaction page.

Running the Sample Code for the Java Transaction API Tip

  1. Download the sample archive for the Java Transaction API tip.

  2. Change to the directory where you downloaded the sample archive. Uncompress the JAR file for the sample archive as follows:
          jar xvf  ttJan2005jta.jar
    The result is a directory called jta with source code, compiled classes, and other supporting files.

  3. Start the application server. The J2EE 1.4 SDK contains the Sun Java System Application Server Platform Edition 8. Note that to work properly, the sample code requires Sun Java Application Server 8.1 4Q2004 or later.

  4. Start the PointBase database server

  5. Change to the jta directory. Edit the Ant script (build.xml) to point to your J2EE home directory.

  6. Enter the command:
          ant create-db
    on the command line. This creates a database and fills it with an "account" table. If the database stalls when trying to dump the table, shut down and restart PointBase.

  7. Enter the command:
          ant build
    This creates a directory called ejb and fills it with two JAR files: bank-client.jar and bank-ejb.jar.

  8. Deploy bank-ejb.jar. You can do this using the Sun Java System Application Server Platform Edition 8 Admin Console, (under Applications->EJB Modules), or by copying the file into the Autodeploy directory link (if you installed the server with that option).

  9. Change to the ejb directory, and enter the following command:
          appclient -client bank-client.jar

In response, you should see the following:

Using Bean Transaction Management (Database Transaction

Balance of 12345-01 is: 100.0
Balance of 12345-02 is: 0.0

Now transferring 23.43 from 12345-01 to 12345-02

Balance of 12345-01 is: 76.57
Balance of 12345-02 is: 23.43

Now transferring 23.43 from 12345-01 to fictional account
number 12345-10
Balance should be the same as before...

Balance of 12345-01 is: 76.57
Balance of 12345-02 is: 23.43

Now Using JTA Container Transaction Management...

Now transferring 23.43 from 12345-01 to fictional account
number 12345-10
Exception was caught.
Balance should again be the same as before...

Balance of 12345-01 is: 76.57
Balance of 12345-02 is: 23.43


Copyright (c) 2004-2005 Sun Microsystems, Inc.
All Rights Reserved.

Parent Category: Java EE Tips