In this article we will review EJB Transaction covering both container and bean-managed transactions that a developer will need to know for the Component Developer Exam. We will first focus on defining transactions within a container-managed or bean-managed context is before we will dive into as well the transaction propagation semantics. Finally we will look at how it fits into the TudoList application.

Understanding EJB Transactions

Despite all the work in designing an excellent domain model, entities that allow you to persist data and web components that allow you to interact with the users, it is not sufficient for your application to be able to stand up to the rigors of working with hundreds of thousands or even millions of users everyday. In order to properly engage with millions of users on a daily basis, your application needs to guarantee that business methods and processes are handled within a transaction. We use transactions on a daily basis. When someone withdraws money from an ATM or pays a utility bill they are engaging in a transaction. All of life is transactional (i.e. a series of exchanges - giving and taking) and business transactions involve a commercial exchange in which the execution is done within a unit of work. In software, transactions will normally access resources available from databases, messaging and web services in order to complete the set of related activities that comprise the unit of work. Transactions can be complex, use large amounts of data and is an all or nothing proposition. Transactions must also provide a degree of reliability and robustness. The term that is used for the properties that a transaction must have is called ACID. Let’s examine what that means.

Atomicity - means either all steps of a transaction or none of them succeed. Transactions are atomic in nature; they either commit or roll back together. This means that if any of the activities fail during the transaction, the set of related activities and data that comprises the unit of work are then aborted and returned to their state before the transaction. Otherwise, if all of the related activities are executed successfully, the transaction is then committed and the changes to the data are made permanent.

Consistency - means a transaction either commits in a valid state to all resources or is rolled back to its original valid state. The most common way of describing what is the consistency property is the following: when a system is in a state consistent with prescribed business rules before the beginning of a transaction, it must be in a consistent state after the transaction is committed or rolled back. A consequence of this is that the system need not be in a consistent state during the transaction. A transaction takes place within well defined boundaries that temporarily shields from the outside world while within it. The boundaries are the beginning and end of the transaction. As long as you are in a consistent state at those times, the state is not important while you are in the transaction.

Isolation - means that transaction changes are are neither visible and the transaction must run without interference from other processes or transactions until the transaction commits. The concept of isolation is similar to the same concept used in thread synchronization or database locking. It is through isolation that we ensure that transactions do not interfere with one another. Basically, we use a transaction manager to prevent another transaction from accessing and changing your data during the transaction. This is critical for concurrent systems where there are a number of processes that can attempt to manipulate the same data at any given time. Isolation in relation to the database is important since a high percentage of transactions are local in nature. It translates into locking data in order to prevent someone else from changing the data during a transaction. Data locks limits the number of concurrent transactions that can run on a system. For this reason there are different isolation strategies that allow one fine grain control over the balance between concurrency and locking, primarily by sacrificing lock acquisition strictness. Each isolation strategy has its own isolation level. The four most common isolation levels, allowing from high to low in terms of concurrency are the following:
  • Read uncommitted—means that the transaction can read the uncommitted data of other transactions, also known as a “dirty” read. Avoid using this level in a multithreaded environment.
  • Read committed—means the transaction will never read uncommitted changes from another transaction. The default level for most databases.
  • Repeatable read—mean the transaction is guaranteed to get the same data on multiple reads of the same rows until the transaction ends.
  • Serializable—provides the highest isolation level as well as guaranteeing that none of the tables you touch will change during the transaction. This includes the addition of any new rows. At this isolation level it is very common to have performance bottlenecks.
Best practice is to use the highest isolation level that provides an acceptable performance level. The isolation level is generally set at the database resource level and not at the EJB level.

Durability - means data that is committed is permanent and will survive any crash of the system. In a transaction, once the transaction is committed, it is guaranteed to become permanent. This is durability. It is usually implemented by using transaction logs in the database server but can also be done by using application server to maintain a transaction log. You might be wondering as to why we would want the database or application to maintain a transaction log. The purpose for the log is that if there is a sudden error during a commit, either the database and/or other systems (such as messaging systems) can be recovered by applying the changes. A database will keep a running record of all data changes made by a transaction before it commits as well a messaging system will ensure that any message not delivered will be resent. Changes made during the transaction are applied again by executing the appropriate entries from the transaction log. This log is the property that facilitates transactions by ensuring that commit really does mean commit.

Using EJB Transactions in TudoList

We are going to extend the TudoList in order that it is able to share Todos and TodoList among different users. In order to make it more interesting we will give the TudoList application a database as well as a Java Messaging Server. This will allow for the creation and distribution of TodoList and Todos among to take place within the same process. In addition the originator of the TodoList and Todos can provide different roles to the different users so that some can modify the TodoList and Todos while others cannot. In he example shown in the figure below, Joe has created a new TodoList and Todo and has shared it among members of his team, Ephraim and Zvi. He has given Ephraim the role of Editor but he has one provided Reader access to Zvi. During the creation of the TodoList and Todo, there are a number of tasks that must be completed by the application for this process to be successful. It must create the TodoList, the Todo, save the entities to the database and submit the entities in the form of messages to the messaging server so that the new TodoList and Todos will be made available to Ephraim and Zvi. Note that because there are two resources to be managed this must be handled in a global transaction. What this means is that we will be required to use a two phase commit in order to ensure that all of the system are updated at the same time. If there was only a database to be updated this could be handled in a local transaction where the commit phase could be done in one step. The figure below show’s the scenario.

Tutorial:Review of EJB Transaction for the Component Developer Exam-a10-tudolisttransactionsystem.jpg
Figure: One Successful and One Failed Transaction


The Internals of Transaction Management

The components that do most of the key work in relation to transaction management are the application servers, database management system as well as component such as messaging servers, enterprise service buses and enterprise informations systems such as SAP. In a database management system, the code around managing a transaction translates into low-level database operations for locking and unlocking rows or tables, beginning a transaction log, committing a transaction by applying log entries, or rolling back a transaction by abandoning the transaction log. With messaging servers, enterprise service buses or enterprise information systems it is the resource manager that manages the transaction for a particular resource.

As was mentioned before most enterprise applications typically use only a single resource. Transaction that use a single resource are called local transactions. When an enterprise application uses two or more resources, such as in the TudoList application where we have both a database and messaging server, it is clear that business application development will require a new kind of abstraction to manage multiple resources within a single transaction. We term transactions within this context as global transactions and they use a transaction manager that coordinates a transaction over multiple distributed resources.

The transaction manager is from the viewpoint of the application either an external component or the application server providing simplified abstraction to transaction services. The TudoList application requests that the transaction manager to start, commit, and roll back transactions. This is shown in the figure below. The transaction manager will coordinates these requests among multiple resource managers, and each transaction phase will translate to numerous low-level resource commands issued by the resource managers. In EJB, transaction are managed across multiple resources via two-phase commits.

Tutorial:Review of EJB Transaction for the Component Developer Exam-a10-distributedtransactionmanagement.jpg
Figure: Distributed Transaction Management in TudoList Application


Looking at Two-phase Commit

The protocol most commonly used to manage transactions in a distributed environment is called the two-phase commit. This is because we need to take precautions before we attempt to commit a transaction involving more than one resource. If we allowed for the database to commit successfully, but the messaging server fails to deliver the message. It would be very difficult to go back and “undo” the changes to the database. To avoid this situation, we use a two-phase commit protocol that performs an additional preparatory step before the final commit. In this preparatory step, each resource manager involved is asked can the current transaction be successfully committed. If any resource manager indicates that the transaction cannot be committed if attempted, the entire transaction is rolled back. If the all clear is given by each resource manager, the transaction is allowed to proceed and all resource managers are asked to commit. One thing that is also necessary is a standard language that can be used to coordinate the two-phase commit across many different kinds of resources, the transaction manager and each of the resource managers. The most commonly used distributed transaction protocol is the XA protocol, which was developed by the X/Open group. Java EE uses this protocol for implementing distributed transaction services. The table below shows the differences between local transactions that involve one resource and a single phase commit protocol and distributed transactions which use a two-phase commit protocol.

Tutorial:Review of EJB Transaction for the Component Developer Exam-a10-localglobaltransactionsdiff.jpg
Table: Differences between Local and Global Transactions


Transaction Management in EJBs

The Java Transaction API provides transaction management support for EJBs. JTA is a small, high-level API that exposes functionality for distributed transaction management by the application server. Most EJB developers will generally use only one JTA interface: javax.transaction.UserTransaction. The reason for this is that the container manages most transaction management details for the developer. So an EJB developer, can simply demarcate the transaction boundaries by telling the container where the transaction begins and ends as well as when to roll back or commit.

The Difference between JTS vs. JTA

Although they are both related to Java EE transaction management. The Java Transaction API (JTA) defines application transaction services as well as the interactions among the application server, the transaction manager, and resource managers where as the Java Transaction Service (JTS) deals with how the transaction manager is implemented. Any JTS transaction manager will support the use of JTA as a high-level interface and will implement the Java mapping of the OMG Object Transaction Service (OTS) specification as its low-level interface. EJB developer will never have to deal directly with JTS.

The Difference between Container-Managed vs Bean-Managed Transactions

The EJB specification provides two means of using transaction, both of which are abstractions over JTA. Container-Managed Transactions (CMT) allow you is to declaratively manage transactions through through annotations or the deployment descriptor. It is the simplest and most flexible means o managing EJB transactions. Bean-managed transaction (BMT) requires you to explicitly manage transactions programmatically. Only session beans and message driven beans support BMT and CMT. The Java Persistence API does not depend on either CMT or BMT but can transparently plug into any transactional environment when you use a container-managed entity manager inside a Java EE container. Let’s look in depth at both options.

Container-Managed Transactions

With container-managed transactions, we allow for the container to start, commit, and roll back a transaction for us. The EJB developer only needs to declare the transaction boundaries of EJB business methods. The container will then start a JTA transaction before a method is invoked, invoke the method, and then depending on whether the method call completed as expected will commit or in case of error roll back the managed transaction. The only requirement is inform the container via annotations or deployment descriptor how to manage the transaction. The default is for the container to assume that CMT is used on all business methods. The key annotations for this are @TransactionManagement and @TransactionAttribute. Let’s look at the use of these annotations using the TudoList application as well as the rollback of a transaction using methods of EJBContext.

TodoList Creation using CMT

Below we implement the scenario of creating a TodoList as a method of a stateless session bean using CMT. With a stateless bean the user creates a TodoList and no state information has to be saved between calls to the TodoListBusinessBean. The bean first sets the timestamp, acquires information on the user creating this TodoList and then creates the new TodoList. I have not gone into the creation of the Entity Access Object that is used for persisting the TodoList entity along with the reference to the User entity. Note how before we declare the bean we provide the annotations indicating that the session bean is stateless as well as container managed. This means that the container will manage the transactions for the bean. Remember that the default is container-managed so actually using the @TransactionManagement annotation or the transaction-type element in the deployment descriptor to inform the container we intend to use a CMT is redundant. Next we inject an EJB context into the bean. And then we indicate that a transaction is required for the createTodoList method. The container will now start a transaction when needed for this method. If for any reason there is an exception in creating the TodoList, the container will roll back the transaction using the injected EJB- Context object’s setRollbackOnly method. The code for this is shown below:

Java Code: Example of CMT Transaction
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER) 
public class TodoListsBusinessBean implements TodoListsBusiness {    
@Resource    
private SessionContext context;
...
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public void void createTodoList(TodoList todoList){
   try { 
        todoList.setLastUpdate(Calendar.getInstance().getTime());
        User user = userBusiness.getCurrentUser();
        todoList.getUsers().add(user);
        todoListEAO.saveTodoList(todoList);
        user.getTodoLists().add(todoList);
        userBusiness.updateUser(user);
   } catch (TodoListCreationException tlce) {
      context.setRollbackOnly();
   } catch (DatabaseException de) {
      context.setRollbackOnly();
   }
}
There are two annotations that are of note. They are:
@TransactionManagement - this specifies whether CMT or BMT is to be used for a particular bean. In the example we specified TransactionManagementType.CONTAINER indicating that the container should manage transactions for the bean. The other option is for the transactions to be managed programmatically. In that case, we would specify TransactionManagementType.BEAN. As noted before, CMT is the default so in most cases you will not need to provide this annotation.
@TransactionAttribute - this is used to tell the container how it should manage transactions. As the transaction which wraps around your bean’s method could be started by the container via a number of different paths such as specifically when you call your method, or via inheritance from a client calling your method (known as joining a transaction) the @TransactionAttribute will tell the container how to handle the situations which could arise when the method is called. It could be that your method could reuse an existing method which has invoked your method or it could be that it is better that the method runs in its own transaction context. This is very important when doing global transactions since you would not want a situation where you reuse for the messaging system a transaction coming from a database. The annotation is applied either to individual CMT bean methods or to the entire bean. When the annotation is applied at the bean, all the business methods will inherit the transaction attribute specified. In our listing above we use TransactionAttributeType.REQUIRED for the createTodoList() method. There are six attributes available for this annotation defined by the enumerated type TransactionAttributeType. They are shown in the table below:

Tutorial:Review of EJB Transaction for the Component Developer Exam-a10-transactionattributes.jpg
Table: Transaction Attributes for EJB Methods


Below is a description of each of the transaction attributes.
  • REQUIRED - is the default for applicable transaction attribute value as well as being the most commonly used. This value states that the EJB method should only be invoked within a transaction. If the method is invoked from in a context without a transaction, the container will start a transaction before the method is called and finish it when the method returns. If there already is a transactional context, the method will join the existing transaction. When transactions are propagated from the client, if the method indicates that the transaction should be rolled back, the container will roll back the whole transaction as well as throw a javax.transaction.RollbackException back to the client. This lets the client know that the transaction it started has been rolled back by another method.
  • REQUIRES_NEW - indicates that the container must always create a new transaction to invoke the EJB method. If there is already a transaction context, it will be temporarily suspended. A new transaction started and finished when our method returns and then the existing transaction context restarted at the point it was suspended. What this implies is that the success or failure of our the transaction has no effect on the existing transaction context. This has limited uses in the real world. If you need a transaction but don’t want a rollback to affect the client of if you don’t want the client’s rollback to affect you. Logging is an example of it effective use where the parent transaction might roll back, but you want to record the failure in your logs. Similarly you don’t want the failure to log a minor debugging message to roll back an entire transaction. This sort of problem should be localized to the logging component.
  • SUPPORTS - this means the EJB method will inherit whatever the transactional environment of the caller is. If there exists a transactional context when the method is invoked, the EJB method will join the existing transaction and won’t cause the exiting transaction to be suspended. But if there is no transactional context when the method is invoked, the EJB method will be called without a transaction. The benefit of this approach is the avoidance of needless overhead in suspending or resuming the client transaction. SUPPORTS attribute is used primarily for methods performing read-only operations like retrieving a record from a database table.
  • MANDATORY - means requires an existing transactional context before calling this EJB method and that the container should never create a transaction on behalf of the client. Otherwise, if an EJB method using the MANDATORY attribute is invoked without a transactional context, the container will throw an EJBTransactionRequiredException. Although it is rarely used. If you want to make ensure that the client fails if a rollback is requested, you should use MANDATORY. For example in a retail application, you should use a MANDATORY transaction on a session bean method that charges the customer. Otherwise you could end up giving away items for free if the client neglects to detect a failure in the method charging the customer, and doesn’t force a roll back when required.
  • NOT_SUPPORTED - this means the EJB method cannot be invoked in a transactional context. If the method is invoked in a transactional context, the container will suspend the transaction, invoke the method, and then resume the transaction after the method returns. This attribute is used primarily with MDBs supporting a JMS provider in non transactional, auto-acknowledge mode where the message is acknowledged as soon as it is successfully delivered. In this case, the MDB has neither the capability nor the need to support rolling back message delivery.
  • NEVER - means exactly what it says, never. The EJB method can never be invoked within a transactional context. If such an attempt is made, a javax.ejb.EJBException is thrown. This is in most cases, the least-used transaction attribute value. One would use it if the method is changing a non- transactional resource like as a text file and you want to ensure the client knows about the non transactional nature of the method.

Using Transaction Attributes with MDBs

Although we use transactions with session beans and message driven beans, not all of the transaction attributes can be used with MDBs. MDBs only supported the REQUIRED and NOT_SUPPORTED attributes. This is because there are no clients ever invoke MDB methods directly. MDBs methods are invoked by the container when it receives an incoming message. So all the transaction attributes related to client transactions or to protect against the container such as REQUIRES_NEW, SUPPORTS, MANDATORY as well as NEVER has no value. Since we only need to concern ourselves with message acknowledgment on method return, there are only two conditions that when we need to pass transaction attributes to the container of two conditions:
  • REQUIRED - for a translation that encapsulates the message listener method
  • NOT_SUPPORTED - when transaction support is not needed

How to Mark a CMT for Rollback

When required a CMT method will inform the container to roll back a transaction as soon as possible. That doesn’t mean that the transaction is not rolled back immediately, instead a flag is set for the container to rollback the transaction when it reaches the end. If we look again at how the rollback is done for the createTodoList() method:

Java Code: Example of CMT Transaction Rollback
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER) 
public class TodoListsBusinessBean implements TodoListsBusiness {    
@Resource    
private SessionContext context;
...
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public void void createTodoList(TodoList todoList){
   try { 
        todoList.setLastUpdate(Calendar.getInstance().getTime());
        User user = userBusiness.getCurrentUser();
        todoList.getUsers().add(user);
        todoListEAO.saveTodoList(todoList);
        user.getTodoLists().add(todoList);
        userBusiness.updateUser(user);
   } catch (TodoListCreationException tlce) {
      context.setRollbackOnly();
   } catch (DatabaseException de) {
      context.setRollbackOnly();
   }
}
The setRollbackOnly method of the injected javax.ejb.EJBContext marks the transaction to be rolled back when the TodoList cannot be created. The TodoListCreationException is thrown and we cannot allow the TodoList to be created. The container starts a new transaction because the createTodoList method is invoked from a non transactional web tier. Because of this, after the method returns, the container will check to see if it can commit the transaction. Since the rollback flag is set for the underlying transaction via the setRollbackOnly method, the container will now roll back the transaction. In this case, the EJB context serves as a proxy to the underlying transaction. Never call the setRollbackOnly method unless you have confirmed there is an underlying transaction to flag. If your method has a transaction attribute of REQUIRED, REQUIRED_NEW, or MANDATORY then you can be sure that the flag has been set. If your method is invoked without a transaction context, the method will throw java.lang.IllegalStateException.
Another EJBContext method you should know about is getRollbackOnly. The method returns a boolean telling you whether the underlying CMT transaction has already been marked for rollback.

Only with the following transaction attributes: REQUIRED, REQUIRES_NEW, or MANDATORY can you invoke the setRollbackOnly and getRollbackOnly methods by an EJB using CMT. Without the proper transaction context, the container will throw an IllegalStateException. There is just one case where you should check the status of the transaction you are participating in. That is when you have a very long, resource-intense operation since you don’t want a method to keep running when it has already thrown an exception. In general you don’t need to call the setRollbackOnly method instead EJB 3 helps in translating exceptions into transaction rollback almost transparent via ApplicationExceptions.

Transactions and Exception Handling

Exceptions can be used to manage transactions in an elegant and intuitive manner. We will use a revised version of the createTodoList method to show how exceptions and transactions can work together:

Java Code: Example of CMT Transaction Exceptions
try { 
        todoList.setLastUpdate(Calendar.getInstance().getTime());
        User user = userBusiness.getCurrentUser();
        todoList.getUsers().add(user);
        todoListEAO.saveTodoList(todoList);
        user.getTodoLists().add(todoList);
        userBusiness.updateUser(user);
   } catch (TodoListCreationException tlce) {
      context.setRollbackOnly();
   } catch (DatabaseException de) {
      context.setRollbackOnly();
   }
The TodoListCreationException, and DatabaseException exceptions serves as the equivalent of the managed transaction being rolled back. EJB 3 has introduced the @javax.ejb.ApplicationException annotation in order to better control the transactional outcome. If we introduce the @ApplicationException mechanism to the createTodoList method for rolling back the container-managed transactions.

Java Code: Example of use of @ApplicationException
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER) 
public class TodoListsBusinessBean implements TodoListsBusiness {    
@Resource    
private SessionContext context;
...
@TransactionAttribute(TransactionAttributeType.REQUIRED) 
public void void createTodoList(TodoList todoList) 
   throws TodoListCreationException, DatabaseException {
        todoList.setLastUpdate(Calendar.getInstance().getTime());
        User user = userBusiness.getCurrentUser();
        todoList.getUsers().add(user);
        todoListEAO.saveTodoList(todoList);
        user.getTodoLists().add(todoList);
        userBusiness.updateUser(user);
...
@ApplicationException(rollback=true)   
public class TodoListCreationException extends Exception{
...
@ApplicationException(rollback=true)   
public class DatabaseException extends RuntimeException{
...
Note how the try-catch blocks have disappeared and now we have a a throws clause in the method declaration. In order to gracefully handle the application exceptions in the client and generate appropriate error messages, the method invocations will throw the two exceptions listed in the throws clause. The key aspect of this is the two @ApplicationException specifications on the custom exceptions which identifies a Java checked or unchecked exception as an application exception. Since in EJB, the client is expected to handle an application exception. The @ApplicationException annotations on TodoListCreationException don’t change the default behavior since it is assumed to be application exception. By default, DatabaseException has been assumed to be a system exception but will be treated as an application exception when the @ApplicationException annotation is applied.

The @ApplicationException annotation itself, changes significantly the default behaviour of a rollback. The default for application exceptions to now provoke an automatic CMT rollback as the rollback element is set to false. But once the rollback is set to true, the container should roll back the transaction before the exception is propagated to the client. In our example, this when the TodoListCreationException or DatabaseException is thrown, the transaction is rolled back and the exception will propagate up to the client indicating the reason for failure. This does the same as the original code that was done programmatically accomplishes. For other system exceptions (i.e. NullPointerException) that were not expected, the container will roll back the CMT. As well since it is expected by the container that the bean is in inconsistent state, the container will destroy the instance. This is an expensive operation, therefore they are to be avoided if at all possible.

Best practice is to use application exceptions for CMT rollback carefully. The setRollbackOnly method allows you to remove the alot of confusion from automated transaction management. This is especially true for developers who lack experience with exception handling with EJBs. This does not mean you should avoid using custom application exceptions. Use it in strategic places throughout your application.

Using the Transaction Lifecycle Events

Transactions have lifecycle events which allow you to be notified when a transaction is started, committed, or rolled back. We do this by having the container-managed bean implement the javax.ejb.SessionSynchronization interface. This interface has the following methods:
  • void afterBegin()—is invoked just after the container creates a new transaction and before the business method is invoked.
  • void beforeCompletion()—is invoked after a business method returns but just before the container ends a transaction.
  • void afterCompletion(boolean committed)—is invoked after the transaction finishes. The boolean committed flag indicates whether a method was committed or rolled back.
This interface is primarily useful for stateful session beans. It is quite useful for loading data into a bean when the transactions starts. As well you can used the afterCompletion callback to reset default values when necessary.

Bean-Managed Transactions

Bean-managed transaction (BMT)allows you to program the details of transaction exactly as you with. This s in contrast to container-managed transactions where you must have the transaction boundaries set at the beginning and end of business methods and rely on the container to control when a transaction starts, commits, or rolls back. The semantics used for BMT is similar to the semantics used for JDBC transactions. The container will still be involved in creating the physical transaction as well as handling a number of low-level details. With BMT, it is important to understand the UserTransaction interface from the JTA transaction API.

TodoList using Bean-Managed Transactions

Let’s transform our previous listing for the original createTodoList method from one using container-managed transaction to bean-managed transaction. I have kept the error handling short for brevity:

Java Code: Example of BMT Transaction
@Stateless
@TransactionManagement(TransactionManagementType.BEAN) 
public class TodoListsBusinessBean implements TodoListsBusiness {    
@Resource    
private UserTransaction userTransaction;

public void void createTodoList(TodoList todoList){
   try{
        userTransaction.begin(); 
        todoList.setLastUpdate(Calendar.getInstance().getTime());
        User user = userBusiness.getCurrentUser();
        todoList.getUsers().add(user);
        todoListEAO.saveTodoList(todoList);
        user.getTodoLists().add(todoList);
        userBusiness.updateUser(user);
        userTransaction.commit();
   } catch (TodoListCreationException tlce) {
      userTransaction.rollback();
   } catch (DatabaseException de) {
      userTransaction.rollback();
   } catch (Exception e) {
      e.printStackTrace();
   }
}
The @TransactionManagement annotation specifies the value TransactionManagementType.BEAN specifying that we are using BMT. There is no need for the @TransactionAttribute annotation since it is valid only for CMT. The UserTransaction is injected into the bean and then used explicitly to begin, commit, or roll back the transaction. In a bean-managed transaction a transaction boundary is much smaller than the entire method and includes only those calls that really need to be atomic.

Obtaining a UserTransaction

The UserTransaction interface is the JTA representation of a bean-managed transaction. It encapsulates the core functionality provided by a Java Enterprise transaction manager. The way to obtain a UserTransaction is via the container. The simplest way is for it to be injected using the @Resource annotation. This is what we did in the listing for the BMT version of the createTodoList method. You can also obtain a UserTransaction instance by using a JNDI lookup or through EJBContext. Below is shown how to obtain a UserTransaction via these two methods.

JNDI Lookup - You just do a lookup via JNDI using java:comp/UserTransaction. The application server has already bound the UserTransaction to this JNDI name. This method is normally used outside of EJBs:

Java Code: Example of JNDI Lookup
 Context context = new InitialContext(); 
UserTransaction userTransaction =
    (UserTransaction) context.lookup("java:comp/UserTransaction"); 
userTransaction.begin(); 
// Perform transacted tasks. 
userTransaction.commit();
EJBContext - You can use the EJBContext to obtain a UserTransaction since it has a method which will return a UserTransaction called getUserTransaction. This method tends to be used when you are already using a SessionContext or MessageDrivenContext. If you want to review information on SessionContext or MessageDrivenContext review either “Tutorial: Review of Session Beans for the Component Developer Exam” or “Tutorial: Review of Message Driven Beans for the Component Developer Exam”. This method is only valid in a BMT environment. In a CMT environment this will cause an IllegalStateException. An IllegalStateException will also be thrown within this context if you use the EJBContext getRollbackOnly or setRollbackOnly methods. The code for using getUserTransaction method is shown below:

Java Code: Example of EJBContext.getUserTransaction
@Resource 
private SessionContext context; 
... 
UserTransaction userTransaction = context.getUserTransaction(); 
userTransaction.begin();
// Perform transacted tasks. 
userTransaction.commit();
Using UserTransaction

Outside of the UserTransaction interface’s methods to begin, commit, and rollback a transaction. There are a number of other methods that are available on the UserTransaction interface. These are shown below.
  • begin(): creates a new transaction. The thread in which the being method is executed is associated with the new transaction and propagated to any EJB that supports existing transaction.
  • commit(): complete the transaction associated with the current thread. When it is execute, the current thread becomes disassociated with the transaction. commit() can throw several checked exceptions such as IllegalStateException if the current thread is no longer associated with the transaction or System Exception if the transaction manager encounters an unexpected condition.
  • rollback(): is invoked to roll back the transaction and to undo updates. It can also throw checked exceptions such as SecurityException if the thread using the UserTransaction object is not allowed to rollback the transaction, or IllegalStateException if the current thread is disassociated with the transaction or finally SystemException if the transaction manage encounters an unexpected error.
  • setRollbackOnly(): is similar to the SessionContext.setRollbackOnly() method in that the transaction is not rolled back immediately but will be on completion of the method.
  • setTransactionTimeout(int): sets the maximum amount of time, in seconds, that a transaction can run before it is aborted.
  • getStatus(): returns a constant indicating the status of the transaction. STATUS_ACTIVE indicates the transaction is active, STATUS_MARKED_ROLLBACK indicates the transaction is doomed possibly as a result of a setRollbackOnly() call.

One thing it is important to remember is that Java EE doesn’t support nested transactions. So you cannot call the begin method two or more times before you invoke the commit or rollback. The second invocation of begin() would throw a NotSupportedException. The getStatus will return the actual state of the transaction.

Tutorial:Review of EJB Transaction for the Component Developer Exam-a10-transactionstatus.jpg
Table: Status Interface Return Values


The setTransactionTimeout() specifies the time limit within that a transaction must finish. Each application server has different default values for the timeout. Oracle Application Server 10g has a default of 30 seconds for example. Others such as JBoss has a transaction timeout value of 300 seconds. This method might be important if you have a long running transaction. Best practices is to simply set the application server-wide defaults using vendor-specific interfaces. This is primarily supported by containers using either an attribute in vendor-specific annotations or the vendor-specific deployment descriptors.

Using CMT vs Using BMT

The default EJB transaction type is container-managed transactions. The best practice for bean-managed transaction is to use them only when required. This is because they tend to be complex, difficult to maintain and verbose. BMT is recommended when you have a stateful session bean that needs to maintain a transaction across method calls (such as a long running transaction). This is difficult to implement and error prone but if you need to go down this route, this can only be done by using BMT. The only other argument for using BMT is if you are looking to fine tune the transaction boundaries so that you minimize the time that data is isolated, then you should consider using BMT. This is primarily an optimization technique and should only be looked at this after your application is developed. In most cases, there are other refactoring methods that can be used to provide better means of optimizing your code.

OK. That’s it. We have looked at the transactions that are both container-managed as well as bean-managed. Next we will tackle EJB Security.