Architecture & DesignSupporting EJB Transactions in Your Java App

Supporting EJB Transactions in Your Java App

Managing transactions in an enterprise application requires making a conscious decision regarding the coordinated flow of persistent data through some sort of application logic. At the low level, a persistent storage system (typically a database) manages the decision when and where to cache data, how to resolve simultaneous access of the same resource, how to resolve errors due to violation of database constraints, and so forth. But then, these issues crop up at the business tier (application server) and client tiers as well. These concerns require special implementation logic for steady performance throughout the application. A full blown EJB transaction support from the underlying framework can leverage the productivity of developers to a great extent. This article explores the concept of EJB transaction management in a Java EE framework.

Transaction Support Overview

Java EE 7 provides Java Transaction API (JTA), specified by JSR 907 through EJBs and Managed Beans. The APIs in thee javax.transaction package define the way to demarcate transaction boundaries with the help of a set of interfaces for the application as well as for the container. It designates the code to start, commit, or roll back in a resource neutral way, implicitly as well as explicitly. In case of a distributed transactional resource, it is handled with the help of XA transactions defined in the package javax.transaction.xa. JTA has been around in the JEE framework for quite some time, but the newest update in the genre is the alignment of a Managed Bean in the transaction process. In a nutshell, keeping aside transaction handling at the database tier, transactions can not only be handled at the business tier but also in the client tier as well through a Managed Bean.

The transaction management support in Java EE7 can be designated into three categories:

  • Container Managed Transaction (CMT)
  • Bean Managed Transaction (BMT)
  • Managed Beans

Container Managed Transaction (CMT)

In CMT, a container is in control and it is the default arena for transaction management. The most important part of its support in EJB is that we can almost forget the complexity involved in describing the internal structure of transaction managers or resource managers. JTA abstracts most of the intricacies and delegates the responsibility of implementing low level transaction protocols to the EJB container. The container acts as a transaction manager involving JTA as well as JTS to participate in distributed transactions with other EJB containers or other transactional resources. The session beans demarcate the transaction boundary, call entities to interact with the database, or send a JMS message in the transaction context.

For example, in the following code snippet there is no visible transaction designation in the form of code. No special interface is implemented nor any annotation applied. This reason is that EJBs are, by default, transactional and the container is solely responsible for managing the transaction using JPA and JTS implicitly.

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class ProductTransactionBean{
   @PersistenceContext(unitName="transactiondemPU")
   private EntityManager entityManager;
   @Inject
   private StockEJB stockEJB;

   public List<Product> getProducts(){
      TypedQuery<Product> query=entityManager
         .createNamedQuery("Product.SELECT_ALL", Product.class);
      return query.getResultList();
   }

   public Product getProductById(int id){
      return entityManager.find(Product.class, id);
   }
   public Product create(Product product){
      if(getProductById(product.getProductId())==null){
         entityManager.persist(product);
         stockEJB.updateStock(product);
      }else{
         stockEJB.updateStock(product);
      }
      return product;
   }
}

As soon as the client makes a request, the container intercepts the call and verifies if any transaction context is associated with the call. The container then begins a new transaction implicitly prior to executing the method. Depending upon the success or failure of the transaction, the container commits or rolls back, respectively. This simple behaviour can, however, be manipulated using metadata expression through either annotation or XML deployment descriptor. The attributes for transaction manipulation are as follows:

  • REQUIRED attribute indicates that the business method must be wrapped around a transaction; otherwise, a new transaction shall be created.
  • REQUIRES_NEW attribute suggest that the container always create a new transaction before executing a method.
  • SUPPORTS indicates that the business method execute as a part of transaction context. However, if the transaction context is unavailable, the container executes the method without transaction context.
  • NOT_SUPPORTED indicates that the business method is not part of any transaction context.
  • MANDATORY indicates that the business method requires a transaction context, but must not create one if unavailable; instead, throw javax.ejb.EJBTransactionRequiredException.
  • NEVER indicates that, if the business process is part of any transaction, a javax.ejb.EJBException will be thrown.

These transaction demarcations can be applied with the help of a @TransactionAttribute annotation, as follows:

@Stateless
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class ProductTransactionBean{
   ...

   @TransactionAttribute(TransactionAttributeType.REQUIRED)
   public Product create(Product product){
      ...
   }
}

In cases where a CMT needs to roll back a transaction, we can use EJB context to intervene the container because a CMT bean is not allowed to roll back explicitly. Demarcating with a EJB context such as session context is just an indication to revert the operation and does not effect immediately while the actual rollback is at the mercy of the container that does the real work when it is time to end the transaction. A session bean with CMT demarcation is only privileged to use this method. An example is as follows:

@Stateless
public class ProductTransactionBean{
   @PersistenceContext(unitName="transactiondemPU")
   private EntityManager entityManager;
   @Resource
   private SessionContext sessionContext;

   public void saleItem(Product product, int quantity){
      Stock stock=product.getStock();
      int qty = stock.getQuantity();
      stock.setQuantity(qty-quantity);
      ...

      entityManager.merge(stock);

      ...

      if(qty==0)
         sessionContext.setRollbackOnly();
   }
}

There is, however, another simple way to inform the container to abort a transaction with the help of an exception, such as:

@Stateless
public class ProductTransactionBean{
   ...

   public void saleItem(Product product, int quantity){
   ...

   if(qty==0)
      throw new MyCustomException();
   }
}

Bean Managed Transaction (BMT)

In BMT, the programmer is in control and can choose to make a pragmatic decision regarding transaction demarcation. Here, a transaction attribute can be specified by using session context to commit or exceptions to roll back a failed transaction. This is particularly useful to attain fine granularity of demarcation policy using JTA explicitly. However, CMT can be easily switched over to BMT with a simple annotation, as follows:

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class ProductTransactionBean{
   ...
}

The core interface to handle BMT is through javax.transaction.UserTransaction. This can be used as follows.

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class ProductTransactionBean{
   @PersistenceContext(unitName="transactiondemPU")
   private EntityManager entityManager;
   @Resource
   private UserTransaction userTransaction;

   ...

   public Product create(Product product){
      try{
         userTransaction.begin();

         if(getProductById(product.getProductId())==null){
            entityManager.persist(product);
            stockEJB.updateStock(product);
         }else{
            stockEJB.updateStock(product);
         }
         userTransaction.commit();
      }catch(Exception ex){
         userTransaction.rollback();
      }
      return product;
   }
}

BMT thus provides a manual override of the transaction scenario, contrasting the container managed transaction in CMT.

Managed Beans

With transaction support in Managed Beans, Java EE 7 extended CMT transactions beyond the EJB arena. Transaction management in Managed Beans is particularly possible due to interceptors and CDI interceptor binding. CDI provided the ability to control transaction boundaries in Servlets, SOAP, and RESTful web services beyond Managed Beans. The core annotation to provide this ability is javax.transaction.Transactional and can be used as follows in a RESTful web service.

@Path("product")
@Transactional
public class ProductRestService{

   @Context
   private UriInfo uriInfo;

   @PersistenceContext(unitName="transactiondemPU")
   private EntityManager entityManager;

   @GET
   @Produces(MediaType.APPLICATION_XML)
   @Trasactional(Transactional.TxType.SUPPORTS)
   public Products getProducts(){
      TypedQuery<Product> query=entityManager
         .createNamedQuery("Product.SELECT_ALL", Product.class);
      Products ps = new Products(query.getResultList());
      return ps;
   }


   @POST
   @Consumes(MediaType.APPLICATION_XML)
   public Response create(Product product){
      entityManager.persist(product);
      URI productUri=uriInfo.getAbsolutePathBuilder()
         .path(product.getProductId().toString()).build();
      return Response.created(productUri).build();
   }
}

Conclusion

This is almost a gross detail of what transaction management is like at the application level implementation in an enterprise arena. There are many subtle aspects and finer details to it, often more than meets the eye. CMT is headache free and the simplest means of transaction management. BMT, on the other hand, provides the means to create a fine grain demarcation policy. CDI binding opened the horizon of transaction processing onto many finer levels, such as Servlets and Web Service, apart from Managed Beans.

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories