Bean-Managed Transactions

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 instead. Although beans with container-managed transactions require less coding, they have one limitation: When a method is executing, it can be associated with either a single transaction or no transaction at all. If this limitation will make coding your bean difficult, you should consider using bean-managed transactions.

The following pseudocode illustrates the kind of fine-grained control you can obtain with bean-managed transactions. By checking various conditions, the pseudocode decides whether to start or stop different transactions within the business method.

begin transaction
...
update table-a
...
if (condition-x)
   commit transaction
else if (condition-y)
   update table-b
   commit transaction
else
   rollback transaction
   begin transaction
   update table-c
   commit transaction 

When coding a bean-managed transaction for session or message-driven beans, you must decide whether to use JDBC or JTA transactions. The sections that follow discuss both types of transactions.

JDBC Transactions

A JDBC transaction is controlled by the transaction manager of the DBMS. You may want to use JDBC transactions when wrapping legacy code inside a session bean. To code a JDBC transaction, you invoke the commit and rollback methods of the java.sql.Connection interface. The beginning of a transaction is implicit. A transaction begins with the first SQL statement that follows the most recent commit, rollback, or connect statement. (This rule is generally true but may vary with DBMS vendor.)

The source code for the following example is in the <INSTALL>/j2eetutorial14/examples/ejb/warehouse/ directory.

The following code is from the WarehouseBean example, a session bean that uses the Connection interface's methods to delimit bean-managed transactions. The ship method starts by invoking setAutoCommit on the Connection object named con. This invocation tells the DBMS not to automatically commit every SQL statement. Next, the ship method calls routines that update the order_item and inventory database tables. If the updates succeed, the transaction is committed. If an exception is thrown, however, the transaction is rolled back.

public void ship (String productId, String orderId, int 
quantity) {

   try {
      makeConnection();
      con.setAutoCommit(false);
      updateOrderItem(productId, orderId);
      updateInventory(productId, quantity);
      con.commit();
   } catch (Exception ex) {
       try {
          con.rollback();
          throw new EJBException("Transaction failed: " +
             ex.getMessage());
       } catch (SQLException sqx) {
           throw new EJBException("Rollback failed: " +
              sqx.getMessage());
       }
    } finally {
        releaseConnection();
    }
}  

Deploying and Running the WarehouseBean Example

WarehouseBean is a session bean that uses bean-managed, JDBC transactions. These steps assume that you are familiar with the steps needed to create and deploy an enterprise application using deploytool, as described in Chapter 25. To deploy and run the example, do the following.

Compiling the WarehouseBean Example

To compile the classes and interfaces in the WarehouseBean example, follow these steps:

  1. In a terminal window, go to this directory:
  2. <INSTALL>/j2eetutorial14/examples/ejb/warehouse/

  3. Create the database tables and data by typing
  4. asant create-db_common


Note: Application Server 8.2 includes a copy of the open source Derby database server. Application Server 8.0/8.1 includes the PointBase database server. If you are using Application Server 8.0/8.1, either follow the instructions in the J2EE Tutorial at http://java.sun.com/j2ee/1.4/docs/tutorial-update6/doc/index.html that works with Application Server 8.0/8.1 or upgrade to Application Server 8.2 (see http://java.sun.com/j2ee/1.4/download.html#appserv to download).


  1. Type the following command to build the enterprise bean's classes and interfaces:
  2. asant build

Packaging the WarehouseBean Example

The WarehouseBean session bean uses bean-managed transactions. These steps assume that you are familiar with the steps needed to create and deploy an enterprise application using deploytool, as described in Chapter 24.

Creating the J2EE Application

Create a new application named WarehouseApp in:

<INSTALL>/j2eetutorial14/examples/ejb/warehouse/  

Packaging the Enterprise Bean

  1. Create a new enterprise bean in WarehouseApp by selecting FileRight ArrowNewRight Arrow Enterprise Bean.
  2. In the EJB JAR screen:
    1. Select Create New JAR Module in Application.
    2. Enter WarehouseJAR under JAR Name.
    3. Click Edit.
    4. Navigate to <INSTALL>/j2eetutorial14/examples/ejb/warehouse/.
    5. Select Warehouse.class, WarehouseBean.class, and WarehouseHome.class.
    6. Click Add.
    7. Click OK.
    8. Click Next.
  3. In the General screen:
    1. Select WarehouseBean under Enterprise Bean Class.
    2. Enter WarehouseBean under Enterprise Bean Name.
    3. Select Stateful Session under Enterprise Bean Type.
    4. Select WarehouseHome under Remote Home Interface.
    5. Select Warehouse under Remote Interface.
    6. Select Next.
  4. Click Finish.
  5. Select WarehouseBean in deploytool's tree.
  6. In the Transactions tab select Bean-Managed under Transaction Management.
  7. In the Resource Ref's tab:
    1. Click Add.
    2. Double-click the Coded Name column for the row that was just created.
    3. Enter jdbc/WarehouseDB.
    4. Under Sun-specific Settings for jdbc/WarehouseDB in the JNDI Name field, select jdbc/ejbTutorialDB.

Packaging the Application Client

  1. Create a new application client in WarehouseApp by selecting FileRight ArrowNewRight ArrowApplication Client.
  2. In the JAR File Contents screen:
    1. Select WarehouseApp under Create New AppClient Module in Application.
    2. Enter WarehouseClient under AppClient Name.
    3. Click Edit.
    4. Navigate to <INSTALL>/j2eetutorial14/examples/ejb/warehouse/.
    5. Select WarehouseClient.class.
    6. Click Add.
    7. Click OK.
    8. Click Next.
  3. In the General screen:
    1. Select WarehouseClient under Main Class.
    2. Select (Use container-managed authentication) under Callback Handler Class.
    3. Click Next.
  4. Click Finish.

Specifying the Application Client's Enterprise Bean Reference

When it invokes the lookup method, WarehouseClient refers to the home of an enterprise bean:

Object objref = 
initial.lookup("java:comp/env/ejb/SimpleWarehouse"); 

You specify this reference as follows:

  1. In the tree, select WarehouseClient.
  2. Select the EJB Ref's tab.
  3. Click Add.
  4. In the Coded Name field, enter ejb/SimpleWarehouse.
  5. In the EJB Type field, select Session.
  6. In the Interfaces field, select Remote.
  7. In the Home Interface field, enter WarehouseHome.
  8. In the Local/Remote Interface field, enter Warehouse.
  9. Click OK.
  10. Select the line you just added.
  11. Under Sun-specific Settings for ejb/SimpleWarehouse, select JNDI Name.
  12. In the JNDI Name field, select WarehouseBean.
  13. Select FileRight ArrowSave.

Deploying the J2EE Application

  1. Select WarehouseApp in deploytool.
  2. Select ToolsRight ArrowDeploy.
  3. Under Connection Settings, enter the user name and password for the Application Server.
  4. Tell deploytool to create a JAR file that contains the client stubs:
    1. Check the Return Client JAR box.
    2. In the field below the checkbox, enter <INSTALL>/j2eetutorial14/examples/ejb/warehouse/.
  5. Click OK.
  6. In the Distribute Module dialog box, click Close when the deployment completes successfully.

Running the Application Client

  1. In a terminal window, go to the <INSTALL>/j2eetutorial14/
    examples/ejb/warehouse/
    directory.
  2. Type the following command:
  3. appclient -client WarehouseAppClient.jar

In the terminal window, the client displays these lines:

status = shipped 

JTA Transactions

JTA is the abbreviation for the Java Transaction API. This API allows you to demarcate transactions in a manner that is independent of the transaction manager implementation. The Application Server implements the transaction manager with the Java Transaction Service (JTS). But your code doesn't call the JTS methods directly. Instead, it invokes the JTA methods, which then call the lower-level JTS routines.

A JTA transaction is controlled by the J2EE transaction manager. You may want to use a JTA transaction because it can span updates to multiple databases from different vendors. A particular DBMS's transaction manager may not work with heterogeneous databases. However, the J2EE transaction manager does have one limitation: it does not support nested transactions. In other words, it cannot start a transaction for an instance until the preceding transaction has ended.

The source code for the following example is in the <INSTALL>/j2eetutorial14/examples/ejb/teller/ directory.

To demarcate a JTA transaction, you invoke the begin, commit, and rollback methods of the javax.transaction.UserTransaction interface. The following code, taken from the TellerBean class, demonstrates the UserTransaction methods. The begin and commit invocations delimit the updates to the database. If the updates fail, the code invokes the rollback method and throws an EJBException.

public void withdrawCash(double amount) {

   UserTransaction ut = context.getUserTransaction();

   try {
      ut.begin();
      updateChecking(amount);
      machineBalance -= amount;
      insertMachine(machineBalance);
      ut.commit();
   } catch (Exception ex) {
       try {
          ut.rollback();
       } catch (SystemException syex) {
           throw new EJBException
              ("Rollback failed: " + syex.getMessage());
       }
       throw new EJBException 
          ("Transaction failed: " + ex.getMessage());
    }
} 

Deploying and Running the TellerBean Example

The TellerBean session bean uses bean-managed JTA transactions. These steps assume that you are familiar with the steps needed to create and deploy an enterprise application using deploytool, as described in Chapter 25. To deploy and run the TellerBean example, perform these steps.

Compiling the TellerBean Example

To compile the classes and interfaces in the TellerBean example, follow these steps:

  1. In a terminal window, go to this directory:
  2. <INSTALL>/j2eetutorial14/examples/ejb/teller/

  3. Create the database tables and data by typing
  4. asant create-db_common


Note: Application Server 8.2 includes a copy of the open source Derby database server. Application Server 8.0/8.1 includes the PointBase database server. If you are using Application Server 8.0/8.1, either follow the instructions in the J2EE Tutorial at http://java.sun.com/j2ee/1.4/docs/tutorial-update6/doc/index.html that works with Application Server 8.0/8.1 or upgrade to Application Server 8.2 (see http://java.sun.com/j2ee/1.4/download.html#appserv to download).


  1. Type the following command to build the enterprise bean's classes and interfaces:
  2. asant build

Packaging the TellerBean Example

The TellerBean session bean uses JTA transactions. These steps assume that you are familiar with the steps needed to create and deploy an enterprise application using deploytool, as described in Chapter 24.

Creating the J2EE Application

Create a new application named TellerApp in

<INSTALL>/j2eetutorial14/examples/ejb/teller/

Packaging the Enterprise Bean

  1. Create a new enterprise bean in TellerApp by selecting FileRight ArrowNewRight Arrow Enterprise Bean.
  2. In the EJB JAR screen:
    1. Select Create New JAR Module in Application.
    2. Enter TellerJAR under JAR Name.
    3. Click Edit.
    4. Navigate to <INSTALL>/j2eetutorial14/examples/ejb/teller/.
    5. Select Teller.class, TellerBean.class, and TellerHome.class.
    6. Click Add.
    7. Click OK.
    8. Click Next.
  3. In the General screen:
    1. Select TellerBean under Enterprise Bean Class.
    2. Enter TellerBean under Enterprise Bean Name.
    3. Select Stateful Session under Enterprise Bean Type.
    4. Select TellerHome under Remote Home Interface.
    5. Select Teller under Remote Interface.
    6. Select Next.
  4. Click Finish.
  5. Select TellerBean in deploytool's tree.
  6. In the Transactions tab select Bean-Managed under Transaction Management.
  7. In the Resource Ref's tab:
    1. Click Add.
    2. Double-click the Coded Name column for the row that was just created.
    3. Enter jdbc/TellerDB.
    4. Under Sun-specific Settings for jdbc/TellerDB in the JNDI Name field, select jdbc/ejbTutorialDB.

Packaging the Application Client

  1. Create a new application client in TellerApp by selecting FileRight ArrowNewRight ArrowApplication Client.
  2. In the JAR File Contents screen:
    1. Select TellerApp under Create New AppClient Module in Application.
    2. Enter TellerClient under AppClient Name.
    3. Click Edit.
    4. Navigate to <INSTALL>/j2eetutorial14/examples/ejb/teller/.
    5. Select TellerClient.class.
    6. Click Add.
    7. Click OK.
    8. Click Next.
  3. In the General screen:
    1. Select TellerClient under Main Class.
    2. Select (Use container-managed authentication) under Callback Handler Class.
    3. Click Next.
  4. Click Finish.

Specifying the Application Client's Enterprise Bean Reference

When it invokes the lookup method, TellerClient refers to the home of an enterprise bean:

Object objref = 
initial.lookup("java:comp/env/ejb/SimpleTeller"); 

You specify this reference as follows:

  1. In the tree, select TellerClient.
  2. Select the EJB Ref's tab.
  3. Click Add.
  4. In the Coded Name field, enter ejb/SimpleTeller.
  5. In the EJB Type field, select Session.
  6. In the Interfaces field, select Remote.
  7. In the Home Interface field, enter TellerHome.
  8. In the Local/Remote Interface field, enter Teller.
  9. Click OK.
  10. Select the line you just added.
  11. Under Sun-specific Settings for ejb/SimpleTeller, select JNDI Name.
  12. In the JNDI Name field, select TellerBean.
  13. Select FileRight ArrowSave.

Deploying the J2EE Application

  1. Select TellerApp in deploytool.
  2. Select ToolsRight ArrowDeploy.
  3. Under Connection Settings, enter the user name and password for the Application Server.
  4. Tell deploytool to create a JAR file that contains the client stubs:
    1. Check the Return Client JAR box.
    2. In the field below the checkbox, enter <INSTALL>/j2eetutorial14/examples/ejb/teller/.
  5. Click OK.
  6. In the Distribute Module dialog box, click Close when the deployment completes successfully.

Running the Application Client

  1. In a terminal window, go to the <INSTALL>/j2eetutorial14/
    examples/ejb/teller/
    directory.
  2. Type the following command:
  3. appclient -client TellerAppClient.jar

In the terminal window, the client displays these lines:

checking = 500.0
checking = 440.0 

Returning without Committing

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.

Methods Not Allowed in Bean-Managed Transactions

Do not invoke the getRollbackOnly and setRollbackOnly methods of the EJBContext interface in bean-managed transactions. These methods should be used only in container-managed transactions. For bean-managed transactions, invoke the getStatus and rollback methods of the UserTransaction interface.