Java EE Transaction SupportThe Java EE container implements support for transactions and facilitates the ACID properties required by the application logic. The container provides an implementation for the two-phase commit protocol between a transaction manager and underlying resources such as the database or messaging provider. The Java EE container is also responsible for the transaction context propagation and provides support for a distributed two-phase commit. With a distributed two-phase commit, a Java EE application can modify data across multiple application servers as if it is a single transaction. The EJB architecture only requires support for flat transactions; however, some of the vendors, such as Arjuna Technologies and Atomikos, provide support for nested transactions. (If nested transactions are not supported and a program creates a nested transaction using the javax.transaction.UserTransaction interface, the container will throw a javax.transaction.NotSupportedException.) The Java Transaction API (JTA) and the Java Transaction Service (JTS) act as fundamental components for Java EE transaction support and transactional interoperability. The JTA API specifies an interface, UserTransaction, used by applications to delineate transaction boundaries. The Java EE transaction model is quite flexible and allows an EJB to participate in an already created transaction or never participate in a transaction depending on the application logic. The UserTransaction is utilized to start and commit and roll back transactions. JTA also defines interfaces used by an application server to communicate with a transaction manager and for a transaction manager to communicate with a resource manager. JTS represents a Java binding of the CORBA Object Transport Service (OTS) specification v1.1. Thus JTS provides transactional interoperability across servers that support the IIOP protocol. Although most of the commercial application servers, such as Sun JES Application Server, BEA's WebLogic, and IBM's WebSphere, implement the JTS API, the EJB specification only mandates JTA API support. Note Despite the theory, JTS/OTS cross-vendor interoperability has always been a problem in practice; this is another reason why many people are looking at Web services technology as the integrating factor. The Java EE specification defines three types of transactional resourcesJDBC connections, JMS sessions, and resources accessed with the Connector Architecture such as Enterprise Resource Planning (ERP) systems. The Java EE container coordinates resource enlistment, the transaction commit, and delistment from the transaction by invoking the corresponding JTA XAResource API. The XAResource interface represents the industry standard XA interface based on the X/Open CAE Specification, [XASPEC]. For more details on this check out the JTA API page [SunJTA]. At the presentation tier, a transaction can be initiated by components such as Java Server Pages or Servlets that can invoke business tier components, such as Enterprise Java Beans, to participate in a transaction. In a database integration scenario, EJBs or even plain old Java objects (POJOs) connect to transactional resource managers via the JDBC connection API. At the Business tier, EJBs or POJOs can span a new transaction connecting directly to a resource manager. The code excerpt that follows demonstrates how to demarcate a transaction in the Presentation tier using JTA. In this example the ProcessRequestServlet uses the javax.transaction.UserTransaction interface to demarcate transaction boundaries. The UserTransaction is obtained via the JNDI interface. Refer to Listing 12-1. Listing 12-1. ProcessRequestService Snippet
Programmatic Transaction SupportPresentation tier components such as Servlets and JSPs can directly connect to the underlying resources, or they may invoke Business tier components. The transaction context is automatically propagated from the Servlet/JSP to the Business tier by the Java EE container, which encapsulates transactional services. At the Business tier the EJB transaction support is quite flexible and allows for two ways to demarcate transactionsdeclaratively Container-Managed Transaction (CMT) and programmatically Bean Managed Transaction model (BMT). For POJOs, transaction demarcation usually has to happen programmatically (although so-called pico-container frameworks like Spring (www.springframework.org) can be used to introduce CMT for POJO-based applications). For EJBs, the javax.ejb.SessionContext (EJBContext) is used to retrieve a UserTransaction. The code fragment here shows how to demarcate transactions with the BMT model. The code encapsulated between the txn.begin() and txn.commit() methods is executed within the scope of a transaction. Refer to Listing 12-2. Listing 12-2. POHandlerEJB Implementation
The txn.begin() call initiates a new transaction. The getConnection() method typically enlists the corresponding XAResource, such as a database, into the transaction. By enlisting the database in the transaction, the database automatically participates in the 2PC protocol. The connection.close() method typically initiates the XAResource.end() method to delist the resource from the transaction. With the txn.commit() call, if it is a 2PC protocol (i.e., if more than one resource have been accessed within the transaction), the XAResource.prepare() and XAResource.commit() are called by the transaction manager. In case of failure or at least one negative prepare, the XAResource.rollback() is called to roll back the transaction in each remaining resource. A reasonably sophisticated transaction manager will also be able to optimize for the common case where only one resource is accessed. In that case, only a one-phase commit is necessary, and the overhead of preparation can be avoided. All this logic is transparent to the Java EE application developer, as can be seen in the code sample. A transaction manager is provided as part of the Java EE application server. The previous example demonstrates how to demarcate transactions in a programmatic manner. Java EE programmatic transaction management is useful when the application relies on a sophisticated level of transaction logic. It is often the case that Java EE applications manage transactions in a declarative manner. Architect's Note The decision for whether to use programmatic or declarative transaction support depends on the level of transaction control and complexity required by the application design. With the declarative transaction support, also known as Container-Managed Transaction demarcation (CMT), boundaries and individual properties of a transaction are specified in a deployment descriptor of Enterprise Java Bean. With programmatic support to a transaction, also known as Bean-Managed Transaction demarcation (BMT), application logic encapsulates transactional characteristics in the code. A Session EJB or a message-driven bean can be designed with either of two demarcation models. An Entity Bean must always be designed with container managed transaction demarcation, whereas a POJO object has to use the programmatic transaction demarcation. (However, it has to be noted that with the introduction of pico-containers and so-called "inversion of control" frameworks, CMT is now also available for POJO applications.) Declarative Transaction ModelWith the declarative model, the Java EE container provides transaction demarcation based on the EJB transaction attributes. Transaction attributes are defined in the bean deployment descriptor and direct the container on how to manage transactions of an enterprise bean method. This model is somewhat similar to the one in .NET. In general, CMT is preferred over BMT because of the following reasons:
CMT also reduces the amount of transaction-related code developers have to write, test, and maintain, which is certainly beneficial in terms of application design. Transaction AttributesThere are six values to choose from. Based on the application design, individual methods of an enterprise bean may have different transactional attribute values. Alternatively, all methods may share the same value or, conversely, none of the methods may support transactions.
The purchase order example implemented with CMT demarcation looks similar to the previous example. There is, however, a significant difference pertaining to the lack of transaction processing code. Refer to Listing 12-3. Listing 12-3. POHandlerEJB Implementation
All transaction processing, such as commit or rollback, is delegated to the Java EE container's transaction manager and specified via transaction attributes. The deployment descriptor corresponding to the POHandlerEJB defines the transaction RequiresNew attribute for all methods of the bean. Transaction attributes can be alternatively defined on a per-method basis. Refer to Listing 12-4. Listing 12-4. Assembly Descriptor for POHandlerEJB
Isolation LevelsBesides the ability to delineate transactional boundaries, the Java EE transaction model provides a mechanism to specify the transaction isolation level. Isolation levels allow or disallow changes made to the data within the scope of a transaction to be visible to other concurrently executed transactions. There are five different transaction isolation levels supported by Java EE:
Transaction isolation levels can be specified based on the type of the underlying resource. For example, for a database access, an enterprise bean implementing the BMT model can set the isolation level using java.sql.Connection interface's setTransactionIsolation (txn IsolationLevel) method . All transaction isolation levels are defined as constant by the java.sql.Connection interface. |