ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


J2EE Transaction Frameworks, Part 3

by Dibyendu Baksi
06/06/2001

The previous two parts of this series discussed the fundamentals of transaction processing in a distributed, component-based environment, as well as the way explicit transaction management is done for the most common J2EE configurations. This part continues the discussion by describing declarative transaction management of session, entity, and message-driven beans. I also describe guidelines for implicit or explicit global transaction management. Finally, local transaction management is described along with common pitfalls and their solutions.

Container-managed transaction

The EJB container is responsible for managing transaction boundaries in the case of declarative transaction management. The way the container manages transactions for a method in an EJB is determined by its transaction attribute. The benefits of using container-managed transactions are listed below.

Even in container-managed demarcation, an EJB has some control over the transaction. For example, an enterprise bean can choose to roll back a transaction started by the container using the method setRollbackOnly on the SessionContext or EntityContext object.

Transaction Attributes

A transaction attribute is a value associated with a method of a session, or an entity bean's remote or home interface, or with the onMessage method of a message-driven bean. It specifies how the container must manage transactions for a method when a client invokes it via the home or remote interface or when the method gets invoked as the result of the arrival of a JMS message. In the majority of cases, all methods of an enterprise bean will have the same transaction attribute. However, it is possible to have different attributes for different methods in the same EJB for special purposes, like when an EJB may have methods that don't need to be transactional.

The transaction attribute must be specified for the following methods:

  • For a session bean, the transaction attributes must be specified for the methods defined in the bean's remote interface and all the direct and indirect superinterfaces of the remote interface, excluding the methods of the javax.ejb.EJBObject interface. Transaction attributes must not be specified for the methods of a session bean's home interface.
  • The description for each type of transaction attribute follows. In the explanations of the different attributes, calling client and parent are meant to be the same as is the called method of the server EJB and child.

    Required

    The container always ensures that the method of the EJB is invoked with a JTA transaction. If the calling client is associated with a JTA transaction, the enterprise bean method will be invoked in the same transaction context. However, if a client is not associated with a transaction, the container will automatically begin a new transaction and try to commit the transaction when the method completes.

    Diagram.
    Figure 1 Transaction propagation in Required

    Required in message driven beans:

    The container invokes a message driven bean method with its transaction attribute set to Required with a valid transaction context. Since there is no client transaction context available for a message-driven bean, the container automatically starts a new transaction before the dequeuing of the JMS message which is before the invocation of the onMessage method. The container automatically enlists the resource manager associated with the arriving message and all the resource managers accessed by the onMessage method with the transaction. If the onMessage method invokes other enterprise beans, the container propagates the transaction context with the invocation. Finally, it attempts to commit the transaction when the onMessage method has completed. In case the onMessage method does not successfully complete, the transaction is rolled back by the container and typical JMS message redelivery semantics apply.

    This is the only scenario in which the interface to the JMS topic or queue is involved in the EJB transaction. For EJBs with the Required attribute, the JMS server will be enlisted as an XAResource. If the JMS server provider does not support XA transactions, the commit or rollback on the JMS session will typically be synchronized with the result of the container's global transaction. In this case, the container will not be able to involve the JMS server in the 2PC process used in managing distributed transactions. A rollback on the JMS session will alert the JMS server that the message should be delivered.

    Handling of setRollbackOnly() method:

    The container must handle the EJBContext.setRollbackOnly() method invoked from a onMessage method executing with the Required transaction attribute by making sure that the transaction will never commit. Typically the transaction manager is instructed by the container to mark the transaction for rollback. When the method invocation completes, the container must roll back rather than commit the transaction. The Container must throw and log the java.lang.IllegalStateException if the EJBContext.setRollbackOnly() method is invoked from an onMessage method executing with the NotSupported transaction attribute

    Handling of getRollbackOnly() method:

    The container must handle the EJBContext.getRollbackOnly() method invoked from an onMessage method by throwing and logging the java.lang.IllegalStateException if the EJBContext.getRollbackOnly() method is invoked from an onMessage method executing with the NotSupported transaction attribute

    Handling of getUserTransaction() method:

    If an instance of a message-driven bean with container-managed transaction demarcation attempts to invoke the getUserTransaction() method of the EJBContext interface, the container must throw and log the java.lang.IllegalStateException.

    RequiresNew

    The container always creates a new transaction before invoking the enterprise bean method and commits the transactions when the method returns. If the calling client is not associated with a transaction context, container will automatically begin a new transaction and try to commit the transaction when the method completes. If the calling client is associated with a transaction context, the container suspends the association of the transaction context with the current thread before starting the new transaction. When the method and the transaction complete, the container resumes the suspended transaction.

    Diagram.
    Figure 2 Transaction propagation in RequiresNew

    NotSupported

    Diagram.
    Figure 3 Transaction propagation in NotSupported

    If the transaction attribute is NotSupported, the transactional context of the calling client is not propagated to the enterprise bean. If a client calls with a transaction context, the container suspends the client's transaction association before invoking the enterprise bean's method. After the method completes, the container resumes the suspended transaction association.

    NotSupported in message driven beans:

    The container invokes a message-driven bean method with its transaction attribute set to NotSupported with an unspecified transaction context. If the onMessage method invokes other enterprise beans, the Container passes no transaction context with the invocation.

    Supports

    Diagram.
    Figure 4 Transaction propagation in Supports

    It the transaction attribute is Supports, and the client is associated with a transaction context, the context is propagated to the enterprise bean method, like the way the container treats the Required case. If the client call is not associated with any transaction context, the container behaves similarly to the NotSupported case. The transaction context is not propagated to the enterprise bean method.

    Mandatory

    Diagram.
    Figure 5 Transaction propagation in Mandatory

    The transaction attribute Mandatory requires the container to invoke a bean's method in a client's transaction context. If the client is not associated with a transaction context when calling this method, the container throws javax.transaction.TransactionRequiredException. If the calling client has a transaction context, the case is treated as Required by the container.

    Never

    Diagram.
    Figure 6 Transaction propagation in Never

    The transaction attribute Never requires that the enterprise bean method not be called within a transaction context. If the client calls with a transaction context, the container throws the java.rmi.RemoteException. If the client is not associated with any transaction context, the container invokes the method without initiating a transaction.

    If an enterprise bean implements the javax.ejb.SessionSynchronization interface, only the following values for the transaction attributes of the bean's methods can be specified: Required, RequiresNew,, or Mandatory.

    This restriction is necessary to ensure that the enterprise bean is invoked only in a transaction. If the bean were invoked without a transaction, the container would not be able to send the transaction synchronization calls. The tools used by the application assembler can determine if the bean implements the javax.ejb.SessionSynchronization interface, for example, by using the Java reflection API on the enterprise bean's class.

    The enterprise bean's business methods or onMessage method must not use any resource manager specific transaction management methods that would interfere with the container's demarcation of transaction boundaries. For example, the enterprise bean methods must not use the following methods of the java.sql.Connection interface: commit(), setAutoCommit(), and rollback(). It must not use the following methods of the javax.jms.Session interface: commit() and roll-back(). The enterprise bean's business methods or onMessage method must not attempt to obtain or use the javax.transaction.UserTransaction interface.

    An enterprise bean with container-managed transaction demarcation can use the setRollbackOnly() method of its EJBContext object to mark the transaction so that the transaction can never commit. Typically an enterprise bean marks a transaction for rollback to protect data integrity before throwing an application exception because they don't automatically cause the container to rollback the transaction. Such a bean can also use the getRollbackOnly() method of its EJBContext object to test if the current transaction has been marked for rollback.

    Deployment descriptor declaration

    The bean provider of a session bean or a message-driven bean must use the transaction-type element to declare whether the session bean or message-driven bean is of the bean-managed or container-managed transaction demarcation type. The transaction-type element is not supported for entity beans because all entity beans must use container-managed transaction demarcation. The bean provider of an enterprise bean with container=managed transaction demarcation may optionally specify the transaction attributes for the enterprise bean's methods.

    This section shows examples of deployment descriptors for specifying transaction attributes for methods of home and remote interfaces of session and entity beans and onMessage methods of message-driven beans. The container-transaction element is used to define transaction attributes. Each container-transaction element consists of a list of one or more method elements and the transattribute element which specifies that all the listed methods are assigned the specified transaction attribute value. All the methods specified in a single container-transaction element be must be methods of the same enterprise bean. The method element uses the ejb-name, method-name, and method-params elements to denote one or more methods of an enterprise bean's home and remote interfaces. There are three legal formats of composing the method element:

    <method>
    <ejb-name>MyEjb</ejb-name>
    <method-name>*</method-name>
    </method>

    Format 1 Deployment Descriptor

    This format is used to specify a default value of the transaction attribute for all the methods. There must be at most one container-transaction element for a given enterprise bean.

    <method>
    <ejb-name>MyEjb</ejb-name>
    <method-name>myMethod</method-name>
    </method>

    Format 2 Deployment Descriptor

    This format is used to refer to a specified method of the remote or home interface of the specified enterprise bean. If there are multiple methods with the same overloaded name, this format refers to all the methods with the same name. There must be at most one container-transaction element for a given method name. If there is also a container-transaction element that uses format-1 element for the same bean, the value specified by the format-2 element takes precedence

    <method>
    <ejb-name>MyEjb</ejb-name>
    <method-name>myMethod</method-name>
    <method-params>
    <method-param>myParameter1</method-param>
    ...
    <method-param>myParameterN</method-param>
    </method-params>
    </method>

    Format 3 Deployment Descriptor

    This format is used to refer to a single method within a set of methods with an overloaded name. The method must be defined in the remote or home interface of the specified enterprise bean. If there is also a container-transaction element that uses the format-2 element for the method name, or the format-1 element for the bean, the value specified by the format-3 element takes precedence. The optional method-intf element can be used to differentiate between methods with the same name and signature that are defined in both the remote and home interfaces.

    The following is an example of the specification of the transaction attributes in the deployment descriptor. The myMethod method of MyEJBean bean is assigned the transaction attribute Mandatory; all other methods of MyEJBean bean are assigned the attribute Required. All the methods of the enterprise bean MyOtherEJBean are assigned the attribute RequiresNew.

    <ejb-jar>
    ...
    <assembly-descriptor>
    ...
    <container-transaction>
    <method>
    <ejb-name>MyEJBean</ejb-name>
    <method-name>*</method-name>
    </method>
    <trans-attribute>Required</trans-attribute>
    </container-transaction>
    <container-transaction>
    <method>
    <ejb-name>MyEJBean</ejb-name>
    <method-name>myMethod</method-name>
    </method>
    <trans-attribute>Mandatory</trans-attribute>
    </container-transaction>
    <container-transaction>
    <method>
    <ejb-name>MyOtherEJBean</ejb-name>
    <method-name>*</method-name>
    </method>
    <trans-attribute>RequiresNew</trans-attribute>
    </container-transaction>
    </assembly-descriptor>
    </ejb-jar>

    Local transaction optimization:

    The container may use a local transaction optimization for enterprise beans whose deployment descriptor indicates that connections to a resource manager are shareable. The container manages the use of the local transaction optimization transparent to the application.

    The container may use the optimization for transactions initiated by the container for a bean with container-managed transaction demarcation and for transactions initiated by a bean with bean-managed transaction demarcation with the UserTransaction interface. The container cannot apply the optimization for a bean with container-managed transaction demarcation if the client invokes the bean with a transaction context that is imported by the container and the bean method has the Required or Mandatory transaction attribute.

    Guidelines in JTA/XA

    The recommended way to manage transactions in J2EE is through container-managed specification. One of the major benefits of the J2EE platform is that it frees the designer and developer of application components from the burden of managing transactions by means of declarative transaction specification. Moreover, the transaction characteristics of an application can be changed with absolutely no modification of the developed code by just changing the transaction attributes in the deployment descriptors. It also results in a separation of roles. Transaction attributes are selected by someone who understands the application well, rather than someone who may just know one part of it. Bean-managed transaction specification is recommended in applications where more control over workflow is needed.

    Choosing transaction attributes:

    Almost all enterprise beans perform transactional work by accessing some form of resource like an EIS or an RDBMS via JDBC. The recommended use of different transaction attributes for enterprise beans taking part in transactional work is given below.

    Local transaction management

    Transactions are specified and handled either by the container (container-managed demarcation) or by a component (component-managed demarcation). In component managed demarcation, an application component can use the JTA UserTransaction interface or a transaction demarcation API specific to an EIS (for example, JDBC transaction demarcation using java.sql.Connection). The EJB specification requires an EJB container to support both container-managed and component-managed transaction demarcation models. The JSP and servlet specifications require a web container to support component-managed transaction demarcation. The requirements demanded from a resource manager and a transaction manager for the transaction management contract are as follows.

    The table below shows the typical combinations one is likely to encounter with transaction managers built into an application server and resource managers. Only the recommended options are shown in the cells. When multiple resource managers participate in a transaction, the EJB container uses a transaction manager to coordinate the transaction. The contract between the transaction manager and resource manager is defined using the XAResource interface. So, if a single resource manager instance participates in either a container-managed or component-managed transaction, the container can choose to do one of the following.

     

    Resource Manager

    NO_TRANSACTION

    Resource Manager

    LOCAL_TRANSACTION

    Resource Manager

    XA_TRANSACTION

    App Server

    NO_TRANSACTION

    -

    Use RML Tran

    Use RML Tran

    App Server

    LOCAL_TRANSACTION

    Use Local JTA

    Use RML Tran

    Use RML Tran

    App Server

    XA_TRANSACTION

    Use Local JTA

    Use RML Tran

    Use JTA/XA Tran

    Diagram.
    Figure 7 Local Transaction on a single Resource Manager

    Local transaction scenarios

    A resource manager local transaction is specific to a particular resource (RDBMS or EIS) connection and is completely managed by the underlying resource manager. The application server with its EJB container and built-in transaction manager has neither any control nor knowledge about any local transactions started by application components. The typical cases when local transactions are involved fall into the following categories.

    Compensating Transactions

    The only way to undo the effect of a mistake made in a transaction is to run another transaction to invert the prior effect of the committed transaction. A compensating transaction is such a group of operations constituting a transaction used to undo the effect of a previously committed transaction. There are instances where multiple accesses to enterprise information systems need to be grouped under a single transaction but not all of the systems support JTA transactions. In such cases it is necessary to define a compensating transaction for each enterprise information system access that is under the scope of a local transaction. If a component needs to access an enterprise information system that does not support JTA transactions or access an enterprise information system that is not supported by a particular J2EE platform, compensating transactions need to be defined.

    In such cases the enterprise information systems are accessed under the scope of resource manager local transactions. If multiple enterprise information systems are involved, this creates the challenge of having to group all the work to multiple enterprise information systems into an atomic unit. For example, suppose an application needs to perform an atomic operation that involves updating three enterprise information systems: two JDBC databases that supports JTA transactions and an enterprise resource planning system that does not. The application would need to define a compensating transaction for the update to the enterprise resource planning system. The approach is illustrated in the following example.

    updateEIS();
    try {
    UserTransaction.begin();
    UpdateJDBC_RDBMS1();
    UpdateJDBC_RDBMS2();
    UserTransaction.commit();
    }
    catch (RollbackException ex) {
    undoUpdateEIS();
    }

    Compensating transaction

    The methods updateEIS(), updateJDBC_RDBMS1(), and updateJDBC_RDBMS2() have implementations to perform work on the EIS, RDBMS1 and RDBMS2 respectively. The undoUpdateEIS() method implements the logic to undo the effect of updateEIS() in case one of the JTA transactions involving RDBMS1 or RDBMS2 does not commit successfully. Ideally this kind of implementation of compensation logic should be encapsulated in a session bean with bean-managed transaction. The transaction attribute of such a session bean should be set to NotSupported if its only responsibility is to access an enterprise information system that does not support JTA transactions. Finally, there are a few important observations that one needs to be careful about in compensating transactions.

    In order to deal with all sorts of potential failures and inconsistencies, any application using compensating transactions must have extra logic implemented. Because of all the complexity and drawbacks of using compensating transactions it should be avoided unless there is no other way to deal with such situations. It is strongly recommended to use JTA/XA transactions as they provide a simple and safe way to achieve the ACID properties across multiple components in multiple tiers accessing multiple relational database management systems or enterprise information systems.

    Conclusion

    This series has barely scratched the surface of a very complex topic encountered in everyday distributed enterprise computing environments. Although some of the core technologies have been around for a while, there is a resurgence of interest with the advent of the large scale web applications being developed in enterprises.

    It's important to understand the choices one needs to make in choosing an application server so that it can work seamlessly with resource managers to provide the best transactional robustness and performance. The key questions to be asked while designing such a system concern which industry standard interfaces are implemented by both the transaction manager (built into the application servers) and the resource managers.

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


    Return to ONJava.com.

    Copyright © 2009 O'Reilly Media, Inc.