Sun Java System Application Server Standard and Enterprise Edition 7 2004Q2 Developer's Guide to Enterprise JavaBeans Technology |
Chapter 6
Handling Transactions with Enterprise BeansThis section describes the transaction support built into the Enterprise JavaBeans (EJBs) programming model for Sun Java System Application Server.
Note
If you are unfamiliar with transaction handling in the EJB technology, refer to the Java Software tutorials:
http://java.sun.com/j2ee/docs.html
Extensive information on EJB transaction support is contained in Chapter 17, “Support for Transactions,” of the Enterprise JavaBeans Specification, v2.0.
Overview material on the Sun Java System Application Server is contained in Sun Java System Application Server and Enterprise JavaBeans Technology and the Sun Java System Application Server Product Introduction.
This section addresses the following topics:
JTA and JTS Transaction SupportJ2EE includes support for distributed transactions through two specifications:
The JTA is a high-level, implementation-independent protocol API that allows applications and application servers to access transactions.
JTS specifies the implementation of a transaction manager which supports the JTA and implements the Java mapping of the OMG Object Transaction Service (OTS) 1.1 specification at the level below the API. JTS propagates transactions using the Internet Inter-ORB Protocol (IIOP).
The current transaction manager implementation supports JTS and the JTA. The EJB container itself uses the Java Transaction API interface to interact with JTS.
The J2EE transaction manager controls all EJB transactions, except for bean-managed Java Database Connectivity (JBDC) transactions, and allows an enterprise bean to update multiple databases within a transaction.
About Transaction HandlingAs a developer, you can write an application that updates data in multiple databases which may be distributed across multiple sites. The site may use EJB servers from different vendors.
This section provides overview information on the following topics:
Flat Transactions
The Enterprise JavaBeans Specification, v2.0 requires support for flat (as opposed to nested) transactions. In a flat transaction, each transaction is decoupled from and independent of other transactions in the system. You cannot start another transaction in the same thread until the current transaction ends.
Flat transactions are the most prevalent model and are supported by most commercial database systems. Although nested transactions offer a finer granularity of control over transactions, they are supported by far fewer commercial database systems.
Global and Local Transactions
Understanding the distinction between global and local transactions is crucial in understanding the Sun Java System Application Server support for transactions.
- Global transactions—Transactions that are managed and coordinated by a resource manager, and can span multiple databases and processes. The resource manager uses the XA two-phase commit protocol to interact with the Enterprise Information System (EIS) or database.
- Local transactions—Transactions that are native to a single EIS or database, use non-XA data sources, and are restricted within a single process. Local transactions do not involve multiple data sources.
Both local and global transactions are demarcated using the javax.transaction.UserTransaction interface, which the client must use. Local transactions bypass the transaction manager and are faster.
Initially, all transactions are local. If a non-XA data source connection is the first resource connection enlisted in a transaction scope, it will become a global transaction when a (second) XA data source connection joins it. If a second non-XA data source connection attempts to join, an exception is thrown.
The Sun Java System Application Server operates in either global or local transaction mode, but the two modes cannot be mixed in the same transaction.
Demarcation Models
As a developer, you can choose between using programmatic transaction demarcation in the EJB code (bean-managed) or declarative demarcation (container-managed). Regardless of whether an enterprise bean uses bean-managed or container-managed transaction demarcation, the burden of implementing transaction management is on the EJB container and the Sun Java System Application Server. The container and the server implement the necessary low-level transaction protocols, such as the two-phase commit protocol between a transaction manager and a dustbowls system or Sun Java System Message Queue, transaction context propagation, and distributed two-phase commit.
These demarcation models are addressed in the following sections:
Container-Managed Transactions
One primary advantage of enterprise beans is the support they provide for container-managed transactions, also known as declarative transactions. In an enterprise bean with container-managed transactions, the EJB container sets the boundaries of the transactions.
Note
You can use container-managed transactions with any type of enterprise bean (session, entity, or message-driven), but an entity bean can only use container-managed transactions.
Container-managed transactions simplify development because the EJB code does not explicitly mark the transaction's boundaries. That is, the code does not include statements that begin and end the transaction. The container is responsible for:
Bean-Managed Transactions
The EJB specification supports bean-managed transaction demarcation, also known as programmer-demarcated transactions, using javax.transaction.UserTransaction. With bean-managed transactions, you must perform a Java Naming and Directory Interface (JNDI) lookup to obtain a UserTransaction object.
Note
You can use bean-managed transactions with session or message-driven beans, but an entity bean must use container-managed transactions.
There are two types of bean-managed transactions:
Commit Options
The EBJ protocol is designed to give the container the flexibility to select the disposition of the instance state at the time a transaction is committed. This allows the container to best manage caching an entity object’s state and associating an entity object identity with the EJB instances.
There are three commit-time options:
The life cycle for every business method invocation under commit option C looks like this:
ejbActivate->
ejbLoad ->
business method ->
ejbStore ->
ejbPassivateIf there is more than one transactional client concurrently accessing the same entity EJBObject, the first client gets the ready instance and subsequent concurrent clients get new instances from the pool.
The Sun Java System Application Server deployment descriptor has an element, commit-option, that specifies the commit option to be used. Based on the specified commit option, the appropriate handler is instantiated.
Administration and Monitoring
An administrator can control the following instance-wide transaction service attributes for the transaction-service element in the server.xml file:
For further explanation on these attributes, refer to the Sun Java System Application Server Administrator’s Configuration File Reference.
In addition, the administrator can monitor transactions using statistics from the transaction manager that provide information on such activities as the number of transactions completed/rolled back/recovered since server startup, and transactions presently being processed.
For information on administering and monitoring transactions, see the Sun Java System Application Server Administration interface online help and the Sun Java System Application Server Administration Guide.
Using Container-Managed TransactionsTypically, the container begins a transaction immediately before an EJB method starts, and commits the transaction just before the method exits. Each method can be associated with a single transaction.
Container-managed transactions do not require all methods to be associated with transactions. When deploying an enterprise bean, you specify which of the bean's methods are associated with transactions by setting the transaction attributes.
Although beans with container-managed transactions require less coding, they have one limitation:
If this limitation will make coding your bean difficult, bean-managed transactions may be your best choice.
When a commit occurs, the transaction signals the container that the bean has completed its useful work and tells the container to synchronize its state with the underlying data source. The container permits the transaction to complete and then frees the bean. Result sets associated with a committed transaction are no longer valid. Subsequent requests for the same bean cause the container to issue a load to synchronize state with the underlying data source.
Any participant can roll back a transaction.
The following sections are related to developing enterprise beans with container-managed transactions:
Specifying Transaction Attributes
A transaction attribute is a parameter that controls the scope of a transaction.
Because transaction attributes are stored in the deployment descriptor, they can be changed during several phases of J2EE application development: at EJB creation, at assembly (packaging), or at deployment. However, as an EJB developer, it is your responsibility to specify the attributes when creating the EJB. The attributes should be modified only when you (or whoever is assembling) are assembling components into larger applications.
Note
Do not expect the person who is deploying the J2EE application to specify the transaction attributes.
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.
For more information, on the EJB deployment descriptor file, refer to “Creating Deployment Descriptors” on page 174.
This section addresses the following topics:
Differing Attribute Requirements
When specifying 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.
Attribute Values
A transaction attribute may have one of the following values:
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.
RequiresNew
If the client is running within a transaction and invokes the EJB's method, the container takes the following steps:
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 EJB's method, the method executes within the client's transaction. If the client is not associated with a transaction, the container throws a TransactionRequiredException.
Use the Mandatory attribute if the EJB's method must use the transaction of the client.
NotSupported
If the client is running within a transaction and invokes the EJB'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.
Supports
If the client is running within a transaction and invokes the EJB'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.
Note
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.
Use the NotSupported attribute for methods that don't need transactions. Because transactions involve overhead, this attribute may improve performance.
The following table summarizes the effects of the transaction attributes. Transactions can be T1, T2, or None. (Both T1 and T2 transactions are controlled by the container.)
- T1 transaction—Is associated with the client that calls a method in the enterprise bean. In most cases, the client is another enterprise bean.
- T2 transaction—Is started by the container, just before the method executes.
- None—In the third column, 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 database.
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 automatically rolls 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 may be initiated by a call to setRollbackOnly.
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.)
A session bean must explicitly reset any instance variables changed within the transaction when a rollback occurs. 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 in session beans, 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.
- 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.
- beforeCompletion method—The container invokes 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).
Methods Not Allowed in Container-Managed Transactions
For container-managed transactions, you should not invoke any method that might interfere with the transaction boundaries set by the container. Prohibited methods are:
You may, however, use these methods to set boundaries in bean-managed transactions.
Using Bean-Managed TransactionsIn a bean-managed transaction, the code in the session or message-driven bean explicitly marks the boundaries of the transaction. By moving transaction management to the bean level, you gain the ability to place all the bean’s activities—even those not directly tied to database access—under the same transaction control as your database calls. This guarantees that all application parts controlled by a bean run as part of the same transaction.
In a failure situation, either everything the bean undertakes is committed, or everything is rolled back.
The following sections are related to developing enterprise beans with bean-managed transactions:
Choosing the Type of Transactions
When coding a bean-managed transaction for session or message-driven beans, you must decide whether to use JDBC or JTA transactions.
Note
In a session bean with bean-managed transactions, it is possible to mix JDBC and JTA transactions. However, this could make your code difficult to debug and maintain.
The following sections discuss both types of transactions:
JDBC Transactions
JDBC transaction is controlled by the transaction manager of the database. 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 database vendor.)
For additional information on JDBC, refer to the Sun Java System Application Server Developer’s Guide to J2EE Services and APIs.
JTA Transactions
JTA allows you to demarcate transactions in a manner that is independent of the transaction manager implementation. The J2EE SDK implements the transaction manager with the 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 database’s transaction manager may not work with heterogeneous databases.
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 previous transaction has ended.
For additional information on the JTA, refer to the Sun Java System Application Server Developer’s Guide to J2EE Services and APIs.
Returning Without Committing
A stateless session bean with bean-managed transactions that has begun a transaction in 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.
Methods Not Allowed in Bean-Managed Transactions
For bean-managed transactions, do not invoke the getRollbackOnly and setRollbackOnly methods of the EJBContext interface. These methods should be used only in container-managed transactions.
Note
For bean-managed transactions, invoke the getStatus and rollback methods of the UserTransaction interface.
Setting Transaction TimeoutsFor container-managed transactions, you control the transaction timeout interval by setting the value of the timeout-in-seconds property in the server.xml file. For example, you would set the timeout value to 5 seconds as follows:
With this setting, if the transaction has not completed within 5 seconds, the EJB container rolls the transaction back.
Handling Isolation LevelsTransactions not only ensure the full completion (or rollback) of the statements that they enclose, but also isolate the data modified by the statements. The isolation level describes the degree to which data being updated is visible to other transactions.
If the transaction allows other programs to read uncommitted data, performance may improve because the other programs don't have to wait until the transaction ends. But this may also cause a problem—if the transaction subsequently rolls back, another program might read the wrong data.
For entity beans with bean-managed persistence and for all session beans, you can set the isolation level programmatically with the API provided by the underlying database. A database, for example, might allow you to permit uncommitted reads by invoking the setTransactionIsolation method.
For entity beans that use container-managed persistence, you can use the consistency element in the sun-cmp-mapping.xml file to set the isolation level.