Java Enterprise in a Nutshell (In a Nutshell (OReilly))

6.9. Transaction Management

One of the advanced value-added features that Enterprise JavaBeans provides over regular remote objects is transaction management. The EJB container can broker transaction contexts on behalf of your EJBs, making sure to "do the right thing" in terms of handling transaction defers, commits, or rollbacks.

The Enterprise JavaBeans architecture relies on the Java Transaction API (JTA ) for transaction support. Chapter 16 provides a general overview of transaction management concepts and the JTA. In that chapter, you'll also find some extended topics related to bean- and container-managed transactions with EJBs. If you're looking for material specifically about transaction management within an EJB context, we recommend that you start with the material in this section and then turn to Chapter 16 if you need to know more about the general concepts of transaction management and the JTA. If you need to delve into the broader context of transaction management in general (e.g., if you need to integrate distributed transactions across multiple resource managers into your application), you may want to start with the general overview provided in Chapter 16, then return to the EJB-specific details provided here.

The EJB container is the principal player in the area of transaction management since it is responsible for either generating transactions around client interactions with the bean or detecting client-requested transactions and then notifying the EJB objects about transaction boundaries (start and commit/rollback). This is another reason all interactions with EJB instances are brokered by the containerso it can properly manage transactions for EJBs that support/require it.

In the context of an Enterprise JavaBeans component, transactions can be defined by any of the three runtime roles that participate in the EJB architecture: the client of the EJB object, the EJB container, or the EJB object itself. In all cases, the EJB container decides how to handle the transaction context whenever a method is invoked on an EJB object. During a bean's lifetime, the container decides whether to execute the bean's business methods within the client's transaction, or within a transaction that the container defines, or to allow the bean to manage its own transaction boundaries. JTA supports what is called a flat transaction model, meaning that transactions can't be nested within each other. If a client defines its own transaction (as shown previously) and invokes an EJB method, which attempts to define its own, separate transaction context, the EJB container needs to decide how to mitigate these two transaction contexts so that there is only one (or else throw an exception if the situation can't be resolved). What the container does in a particular transactional situation is determined largely by deployment descriptor elements that indicate how an EJB transaction is to be managed.

6.9.1. Transaction Management: Bean-Managed Versus Container-Managed

First, at a high level, you need to specify to the container whether your EJB will manage its own transactions (by creating its own UserTransaction objects and starting/committing them in its business methods) or will rely on the container to manage its transactions. This is done in the deployment descriptor using the <transaction-type> element:

... <enterprise-beans> <session> ... <transaction-type>Container</transaction-type> ... </session> ... </enterprise-beans> ...

A Container value indicates container-managed transactions; a Bean value indicates bean management. If you specify bean-managed transactions, the container will automatically suspend any client-defined transactions before calling methods on your EJB and resume them after any bean-defined transaction contexts have been committed/rolled back. If you use container-managed transactions, the container will use the method-level transaction support attributes discussed in the next section to determine how it deals with transactions. Normally you will want to use container-managed transactions since managing your own transaction boundaries within your bean code isn't usually necessary. Bean-managed transactions may be necessary when you need to define multiple transaction contexts in the span of a single method. But situations like this are rare, and where possible you should avoid the additional complexity in your code and leave the transaction management to the EJB container.

Entity beans aren't allowed to use bean-managed transaction management because the persistence management services of the EJB container require that entity beans never create their own UserTransactions. So you never specify a <transaction-type> for entity beans in their deployment descriptor; it's always assumed to be Container.

6.9.2. Transaction Support Attributes

If your EJB uses container-managed transaction management, you can further specify how each method on the EJB "supports" transactions, and therefore how the container should deal with different transaction contexts when it invokes these methods on your beans. The following <transaction-support> values are available when specifying them in your deployment descriptor:

NotSupported

The method can't support transactions, so it must be called without a transaction context. If the client has initiated a transaction, it is suspended by the container before the bean's method is invoked. After the method completes, the container resumes the client's transaction. The container doesn't define its own transaction context for the method call, so if the EJB calls other EJBs from the method, no transaction context is passed along to these methods.

Supports

The method supports transactions if requested. If the client calls a method on the bean while within a transaction, the method is invoked within the client's transaction context; this transaction will be passed on to any other EJB methods called within this method. If the client calls the method with no transaction context, the container doesn't create one; it runs the method with no transaction context.

Required

The method must be executed within a transaction context. If the client is already in a transaction of its own, the transaction context is used to invoke the EJB method. If not, the container creates a new transaction before calling the bean's method and commits/rolls back the transaction when the bean's method finishes, but before the method results are returned to the client.

RequiresNew

The method must be executed within a new transaction. The container automatically starts a new transaction before calling a remote method on the bean, and commits the transaction when the method finishes, but before the results are returned to the client. If the client calls a remote method while within a transaction, the client's transaction is suspended by the container before executing the bean's method within the new transaction and resumed after the new transaction is committed.

Mandatory

The method must be run within the context of a client-initiated transaction. If the client calls the method on the bean without starting a transaction first, the container throws a javax.transaction.TransactionRequiredException if the client is remote. It throws a javax.ejb.TransactionRequiredLocalException for local clients.

Never

The method must never be called with a transaction context. If a client calls this method from within its own transaction, the container will throw an exception back to the client (java.rmi.RemoteException if the client is remote, javax.ejb.EJBException if the client is local).

These attributes are associated with methods on the EJB in the <assembly-descriptor> section of the deployment descriptor. You provide <container-transaction> elements that specify one or more methods and a transaction support attribute to apply to those methods. Using our stateless session ProfileManager EJB as an example, we can specify that its getProfile( ) method "supports" transactions using this XML stanza:

... <assembly-descriptor> ... <container-transaction> <method> <ejb-name>ProfileManagerBean</ejb-name> <method-name>getProfile</method-name> </method> <trans-attribute>Supports</trans-attribute> </container-transaction> ... </assembly-descriptor> ...

There are some restrictions on the use of these attribute values for some types of EJBs, as described next.

6.9.2.1. Message-driven beans

For message-driven beans, only the NotSupported and Required attributes are allowed since client transactions can't be propagated to the EJB through a message passed to a JMS service.

6.9.2.2. CMP entity beans

Entity beans using CMP use transactions by definition when the container interacts with the persistent store on their behalf. Therefore, entity EJBs using CMP should use either the Required, RequiresNew, or Mandatory attributes since the others allow for contexts with no transactions. Technically, you can use the other attribute values with CMP beans, but EJB containers are not required to support them in this situation, so it's wise to avoid them.

6.9.2.3. Stateful session beans

Stateful session beans that implement the session synchronization interface, as discussed at the end of "Session Bean Specifics" earlier in this chapter, depend on transaction notifications from the container to keep their state in sync. Without a transaction, the container is not able to invoke the session synchronization callbacks. Therefore, this flavor of stateful session bean can use only attribute values that result in a transaction: Required, RequiresNew, and Mandatory.

6.9.2.4. Stateless session beans

If a stateless session bean is published as a web service (as detailed in Chapter 12), you are not allowed to use the Mandatory attribute value. A transaction context initiated by a SOAP client cannot be propagated across a SOAP call to the session bean, so mandating that the client initiate a transaction for the bean request doesn't make sense.

Категории