Download PDF Home History |  | API Search Feedback FAQ

> ## Container-Managed Transactions

> In an enterprise bean with container-managed transactions, the EJB container sets the boundaries of the transactions. You can use container-managed transactions with any type of enterprise bean: session, entity, or message-driven. Container-managed transactions simplify development because the enterprise bean code does not explicitly mark the transaction's boundaries. The code does not include statements that begin and end the transaction.

> Typically, the container begins a transaction immediately before an enterprise bean method starts. It commits the transaction just before the method exits. Each method can be associated with a single transaction. Nested or multiple transactions are not allowed within a method.

> Container-managed transactions do not require all methods to be associated with transactions. When deploying a bean, you specify which of the bean's methods are associated with transactions by setting the transaction attributes.

> ### Transaction Attributes

> A transaction attribute controls the scope of a transaction. Figure 30-1 illustrates why controlling the scope is important. In the diagram, `method-A` begins a transaction and then invokes `method-B` of `Bean-2`. When `method-B` executes, does it run within the scope of the transaction started by `method-A`, or does it execute with a new transaction? The answer depends on the transaction attribute of `method-B`.

> Figure 30-1 Transaction Scope

> A transaction attribute can have one of the following values:

> - `Required`
> - `RequiresNew`
> - `Mandatory`
> - `NotSupported`
> - `Supports`
> - `Never`

> #### Required

> If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container starts a new transaction before running the method.

> The `Required` attribute will work for most transactions. Therefore, you may want to use it as a default, at least in the early phases of development. Because transaction attributes are declarative, you can easily change them later.

> #### RequiresNew

> If the client is running within a transaction and invokes the enterprise bean's method, the container takes the following steps:

> 1. Suspends the client's transaction
> 2. Starts a new transaction
> 3. Delegates the call to the method
> 4. Resumes the client's transaction after the method completes

> If the client is not associated with a transaction, the container starts a new transaction before running the method.

> You should use the `RequiresNew` attribute when you want to ensure that the method always runs within a new transaction.

> #### Mandatory

> If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container throws the `TransactionRequiredException`.

> Use the `Mandatory` attribute if the enterprise bean's method must use the transaction of the client.

> #### NotSupported

> If the client is running within a transaction and invokes the enterprise bean's method, the container suspends the client's transaction before invoking the method. After the method has completed, the container resumes the client's transaction.

> If the client is not associated with a transaction, the container does not start a new transaction before running the method.

> Use the `NotSupported` attribute for methods that don't need transactions. Because transactions involve overhead, this attribute may improve performance.

> #### Supports

> If the client is running within a transaction and invokes the enterprise bean's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container does not start a new transaction before running the method.

> Because the transactional behavior of the method may vary, you should use the `Supports` attribute with caution.

> #### Never

> If the client is running within a transaction and invokes the enterprise bean's method, the container throws a `RemoteException`. If the client is not associated with a transaction, the container does not start a new transaction before running the method.

> #### Summary of Transaction Attributes

> Table 30-1 summarizes the effects of the transaction attributes. Both the T1 and the T2 transactions are controlled by the container. A T1 transaction is associated with the client that calls a method in the enterprise bean. In most cases, the client is another enterprise bean. A T2 transaction is started by the container just before the method executes.

> In the last column of Table 30-1, the word None means that the business method does not execute within a transaction controlled by the container. However, the database calls in such a business method might be controlled by the transaction manager of the DBMS.

> #### Setting Transaction Attributes

> Because transaction attributes are stored in the deployment descriptor, they can be changed during several phases of J2EE application development: enterprise bean creation, application assembly, and deployment. However, it is the responsibility of an enterprise bean developer to specify the attributes when creating the bean. The attributes should be modified only by an application developer who is assembling components into larger applications. Do not expect the person deploying the J2EE application to specify the transaction attributes.

> Table 30-1 Transaction Attributes and Scope
> Transaction Attribute | Client's Transaction | Business Method's Transaction
> --- | --- | ---
> `Required` | None | T2
> T1 | T1
> `RequiresNew` | None | T2
> T1 | T2
> `Mandatory` | None | error
> T1 | T1
> `NotSupported` | None | None
> T1 | None
> `Supports` | None | None
> T1 | T1
> `Never` | None | None
> T1 | Error

> You can specify the transaction attributes for the entire enterprise bean or for individual methods. If you've specified one attribute for a method and another for the bean, the attribute for the method takes precedence. When you specify attributes for individual methods, the requirements differ with the type of bean. Session beans need the attributes defined for business methods but do not allow them for the `create` methods. Entity beans require transaction attributes for the business, `create`, `remove`, and finder methods. Message-driven beans require transaction attributes (either `Required` or `NotSupported`) for the `onMessage` method.

> ### Rolling Back a Container-Managed Transaction

> There are two ways to roll back a container-managed transaction. First, if a system exception is thrown, the container will automatically roll back the transaction. Second, by invoking the `setRollbackOnly` method of the `EJBContext` interface, the bean method instructs the container to roll back the transaction. If the bean throws an application exception, the rollback is not automatic but can be initiated by a call to `setRollbackOnly`. For a description of system and application exceptions, see deploytool Tips for Entity Beans with Bean-Managed Persistence.

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

> The `transferToSaving` method of the `BankBean` example illustrates the `setRollbackOnly` method. If a negative checking balance occurs, `transferToSaving` invokes `setRollBackOnly` and throws an application exception (`InsufficientBalanceException`). The `updateChecking` and `updateSaving` methods update database tables. If the updates fail, these methods throw an `SQLException` and the `transferToSaving` method throws an `EJBException`. Because the `EJBException` is a system exception, it causes the container to automatically roll back the transaction. Here is the code for the `transferToSaving` method:

>     public void transferToSaving(double amount) throws
>        InsufficientBalanceException  {

>        checkingBalance -= amount;
>        savingBalance += amount;

>        try {
>           updateChecking(checkingBalance);
>           if (checkingBalance < 0.00) {
>              context.setRollbackOnly();
>              throw new InsufficientBalanceException();
>           }
>           updateSaving(savingBalance);
>        } catch (SQLException ex) {
>            throw new EJBException
>               ("Transaction failed due to SQLException: "
>               + ex.getMessage());
>        }
>     }

> When the container rolls back a transaction, it always undoes the changes to data made by SQL calls within the transaction. However, only in entity beans will the container undo changes made to instance variables. (It does so by automatically invoking the entity bean's `ejbLoad` method, which loads the instance variables from the database.) When a rollback occurs, a session bean must explicitly reset any instance variables changed within the transaction. The easiest way to reset a session bean's instance variables is by implementing the `SessionSynchronization` interface.

> ### Synchronizing a Session Bean's Instance Variables

> The `SessionSynchronization` interface, which is optional, allows you to synchronize the instance variables with their corresponding values in the database. The container invokes the `SessionSynchronization` methods--`afterBegin`, `beforeCompletion`, and `afterCompletion`--at each of the main stages of a transaction.

> The `afterBegin` method informs the instance that a new transaction has begun. The container invokes `afterBegin` immediately before it invokes the business method. The `afterBegin` method is a good place to load the instance variables from the database. The `BankBean` class, for example, loads the `checkingBalance` and `savingBalance` variables in the `afterBegin` method:

>     public void afterBegin() {

>        System.out.println("afterBegin()");
>        try {
>           checkingBalance = selectChecking();
>           savingBalance = selectSaving();
>        } catch (SQLException ex) {
>            throw new EJBException("afterBegin Exception: " +
>                ex.getMessage());
>        }
>     }

> The container invokes the `beforeCompletion` method after the business method has finished, but just before the transaction commits. The `beforeCompletion` method is the last opportunity for the session bean to roll back the transaction (by calling `setRollbackOnly`). If it hasn't already updated the database with the values of the instance variables, the session bean can do so in the `beforeCompletion` method.

> The `afterCompletion` method indicates that the transaction has completed. It has a single `boolean` parameter whose value is `true` if the transaction was committed and `false` if it was rolled back. If a rollback occurred, the session bean can refresh its instance variables from the database in the `afterCompletion` method:

>     public void afterCompletion(boolean committed) {

>        System.out.println("afterCompletion: " + committed);
>        if (committed == false) {
>           try {
>              checkingBalance = selectChecking();
>              savingBalance = selectSaving();
>           } catch (SQLException ex) {
>               throw new EJBException("afterCompletion SQLException:
>           " + ex.getMessage());
>           }
>        }
>     }

> ### Compiling the BankBean Example

> To compile the classes and interfaces in the `BankBean` example, follow these steps:

> 1. In a terminal window, go to this directory:

> `<``INSTALL``>/j2eetutorial14/examples/ejb/bank/`

> 2. Start the PointBase server. For instructions, see Starting and Stopping the PointBase Database Server.
> 3. Create the database tables and data by typing

> `asant create-db_common`

> 4. Type the following command to build the enterprise bean's classes and interfaces:

> `asant build`

> ### Packaging the BankBean Example

> The `BankBean` session bean uses container-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 `BankApp` in:

>     <INSTALL>/j2eetutorial14/examples/ejb/bank/

> #### Packaging the Enterprise Bean

> 1. Create a new enterprise bean in `BankApp` by selecting FileNewEnterprise Bean.
> 2. In the EJB JAR screen:
> 1. Select Create New JAR Module in Application.
> 2. Enter `BankJAR` under JAR Name.
> 3. Click Edit.
> 4. Navigate to `<``INSTALL``>/j2eetutorial14/examples/ejb/bank/build/`.
> 5. Select `Bank.class`, `BankBean.class`, `BankHome.class`, and `InsufficientBalanceException.class`.
> 6. Click Add.
> 7. Click OK.
> 8. Click Next.
> 3. In the General screen:
> 1. Select `BankBean` under Enterprise Bean Class.
> 2. Enter `BankBean` under Enterprise Bean Name.
> 3. Select Stateful Session under Enterprise Bean Type.
> 4. Select `BankHome` under Remote Home Interface.
> 5. Select `Bank` under Remote Interface.
> 6. Select Next.
> 4. Click Finish.
> 5. Select `BankBean` in `deploytool`'s tree.
> 6. In the Resource Ref's tab:
> 1. Click Add.
> 2. Set the Coded Name to `jdbc/BankDB`.
> 3. Set the JNDI Name to `jdbc/ejbTutorialDB`.
> 7. In the Transactions tab:
> 1. Select Container-Managed under Transaction Management.
> 2. Verify that `getCheckingBalance()`, `getSavingBalance()`, and `transferToSaving()` have the `Required` transaction attribute.

> #### Packaging the Application Client

> 1. Create a new application client in `BankApp` by selecting FileNewApplication Client.
> 2. In the JAR File Contents screen:
> 1. Select `BankApp` under Create New AppClient Module in Application.
> 2. Enter `BankClient` under AppClient Name.
> 3. Click Edit.
> 4. Navigate to `<``INSTALL``>/j2eetutorial14/examples/ejb/bank/build/`.
> 5. Select `BankClient.class`.
> 6. Click Add.
> 7. Click OK.
> 8. Click Next.
> 3. In the General screen:
> 1. Select `BankClient` 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, `BankClient` refers to the home of an enterprise bean:

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

> You specify this reference as follows:

> 1. In the tree, select `BankClient`.
> 2. Select the EJB Refs tab.
> 3. Click Add.
> 4. In the Coded Name field, enter `ejb/SimpleBank`.
> 5. In the EJB Type field, select `Session`.
> 6. In the Interfaces field, select `Remote`.
> 7. In the Home Interface field, enter `BankHome`.
> 8. In the Local/Remote Interface field, enter `Bank`.
> 9. Click OK.
> 10. Select the line you just added.
> 11. Under Sun-specific Settings for `ejb/SimpleBank`, select JNDI Name.
> 12. In the JNDI Name field select, `BankBean`.
> 13. Select FileSave.

> #### Deploying the J2EE Application

> 1. Select `BankApp` in `deploytool`.
> 2. Select ToolsDeploy.
> 3. Under Connection Settings, enter the user name and password for the Sun Java System Application Server Platform Edition 8.
> 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/bank/`.
> 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/bank/` directory.
> 2. Type the following command:

> `appclient -client BankAppClient.jar`

> In the terminal window, the client displays these lines:

>     checking: 60.0
>     saving: 540.0

> ### Methods Not Allowed in Container-Managed Transactions

> You should not invoke any method that might interfere with the transaction boundaries set by the container. The list of prohibited methods follows:

> - The `commit`, `setAutoCommit`, and `rollback` methods of `java.sql.Connection`
> - The `getUserTransaction` method of `javax.ejb.EJBContext`
> - Any method of `javax.transaction.UserTransaction`

> You can, however, use these methods to set boundaries in bean-managed transactions.

Download PDF Home History |  | API Search Feedback FAQ

All of the material in The J2EE(TM) 1.4 Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.