|Sun ONE Application Server 7 Developer's Guide to Enterprise Java Beans Technology|
Handling Transactions with Enterprise Beans
This section describes the transaction support built into the Enterprise JavaBeans (EJBs) programming model for Sun ONE Application Server 7.
If you are unfamiliar with transaction handling in the EJB technology, refer to the Java Software tutorials:
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 ONE Application Server is contained in "Introducing the Sun ONE Application Server Enterprise JavaBeans Technology" and the Sun ONE Application Server Product Introduction.
This section addresses the following topics:
- JTA and JTS Transaction Support
- Using Container-Managed Transactions
- Using Bean-Managed Transactions
- Setting Transaction Timeouts
- Handling Isolation Levels
JTA and JTS Transaction Support
J2EE 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 Handling
As 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
- Global and Local Transactions
- Demarcation Models
- Commit Options
- Administration and Monitoring
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 ONE Application Server support for transactions.
- Global transactionsTransactions that are managed and coordinated by a resource manager, and can span multiple databases and processes. The resource manager typically uses the XA two-phase commit protocol to interact with the Enterprise Information System (EIS) or database.
- Local transactionsTransactions that are native to a single EIS or database 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 ONE Application Server operates in either global or local transaction mode, but the two modes cannot be mixed in the same transaction.
If your application uses global transactions, you must configure and enable the corresponding Sun ONE Application Server resource managers. For more information, see the Sun ONE Application Server Administration interface online help and the and Administrator's Guide.
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 ONE 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 ONE Message Queue provider, transaction context propagation, and distributed two-phase commit.
These demarcation models are addressed in the following sections:
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.
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:
- Demarcating and transparently propagating the transactional context
- In conjunction with a transaction manager, ensuring that all participants in the transaction see a consistent outcome
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.
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:
- JDBC typeYou delimit JDBC transactions with the commit and rollback methods of the connection interface.
- JTA typeYou invoke the begin, commit, and rollback methods of the UserTransaction interface to demarcate JTA transactions.
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:
- Option AThe container caches a ready instance between transactions. The container ensures that the instance has exclusive access to the state of the object in persistent storage.
In this case, the container does not have to synchronize the instance's state from the persistent storage at the beginning of the next transaction.
Commit option A is not supported for Sun ONE Application Server 7.
- Option BThe container caches a ready instance between transactions, but the container does not ensure that the instance has exclusive access to the state of the object in persistent storage. This is the default.
In this case, the container must synchronize the instance's state by invoking ejbLoad from persistent storage at the beginning of the next transaction.
- Option CThe container does not cache a ready instance between transactions, but instead returns the instance to the pool of available instances after a transaction has completed.
The life cycle for every business method invocation under commit option C looks like this:
business method ->
If 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 ONE 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.
It is assumed that if commit option A is used, the developer is responsible for ensuring that only this application is updating the database. In other words, this is not the container's responsibility.
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 ONE 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 ONE Application Server Administration interface online help and the Sun ONE Application Server Administrator's Guide.
Using Container-Managed Transactions
Typically, 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.
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 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:
When a method is executing, it can only be associated with either a single transaction or no transaction at all.
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.
Transactions initiated by the container are implicitly committed.
Any participant can roll back a transaction.
The following sections are related to developing enterprise beans with container-managed transactions:
- Specifying Transaction Attributes
- Rolling Back a Container-Managed Transaction
- Synchronizing a Session Bean's Instance Variables
- Methods Not Allowed in 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.
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.
If you're unsure about how to set up transactions in the EJB's deployment descriptor, specify container-managed transactions. Then, set the Required transaction attribute for the entire enterprise bean. This approach will work most of the time.
For more information, on the EJB deployment descriptor file, refer to "Creating Deployment Descriptors".
This section addresses the following topics:
Differing Attribute Requirements
When specifying attributes for individual methods, the requirements differ with the type of bean.
- Session beansNeed the attributes defined for business methods, but do not allow them for the create methods.
- Entity beansRequire transaction attributes for the business, create, remove, and finder methods.
- Message-driven beansRequire transaction attributes (either Required or NotSupported) for the onMessage method.
A transaction attribute may have one of the following values:
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 at a later time.
If the client is running within a transaction and invokes the EJB's method, the container takes the following steps:
- Suspends the client's transaction.
- Starts a new transaction.
- Delegates the call to the method.
- 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.
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.
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.
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.
Because the transactional behavior of the method may vary, you should use the Supports attribute with caution.
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. The left column lists the transaction attribute, the middle column lists the type of client transaction, and the right column lists the transaction type of the business method. Transactions can be T1, T2, or None. (Both T1 and T2 transactions are controlled by the container.)
- T1 transactionIs associated with the client that calls a method in the enterprise bean. In most cases, the client is another enterprise bean.
- T2 transactionIs started by the container, just before the method executes.
- NoneIn 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.
Transaction Attributes and Scope
Business Method's Transaction
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 methodsafterBegin, beforeCompletion, and afterCompletionat each of the main stages of a transaction.
- afterBegin methodInforms 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 methodThe 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).
If it hasn't already updated the database with the values of the instance variables, the session bean may do so in the beforeCompletion method.
- afterCompletion methodIndicates 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.
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:
- The commit, setAutoCommit, and rollback methods of java.sql.Connection
- The getUserTransaction method of javax.ejb.EJBContext
- Any method of javax.transaction.UserTransaction
You may, however, use these methods to set boundaries in bean-managed transactions.
Using Bean-Managed Transactions
In 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 activitieseven those not directly tied to database accessunder 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
- Returning Without Committing
- Methods Not Allowed in 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.
In a session bean with bean-managed transactions, it is possible to mix JDBC and JTA transactions. This practice is not recommended, however, because it could make your code difficult to debug and maintain.
The following sections discuss both types of 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 ONE Application Server Developer's Guide to J2EE Features and Services.
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 limitationit 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 ONE Application Server Developer's Guide to J2EE Features and Services.
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 transactionThe 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.
For bean-managed transactions, invoke the getStatus and rollback methods of the UserTransaction interface.
Setting Transaction Timeouts
For 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.
Only enterprise beans using container-managed transactions are affected by the timeout-in-seconds property. For enterprise beans using bean-managed JTA transactions, you invoke the setTransactionTimeout method of the UserTransaction interface.
Handling Isolation Levels
Transactions 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 the 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 problemif 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.
Do not change the isolation level in the middle of a transaction. Usually, such a change causes the database software to issue an implicit commit. Because the isolation levels offered by database vendors may vary, you should check the database documentation for more information. Isolation levels are not standardized for the J2EE platform.