Transaction represents a group of activities that must be performed as a single work unit. This clarifies that a transaction is complete if and only if all the work items within a work group results in success. If any of the work items fails, then the transaction as a whole will be treated as a failure. Managing transactions is vital not only for Enterprise applications but also for any flavour of applications. In this article we will explore the various services provided by the EJB container with respect to transaction management. This article assumes that the reader has a basic understanding on EJB technology such the various EJB containers, enterprise beans etc along with the fundamental concepts of transactions such as ACID properties, commit and rollback.
also read:
Container managed transactions in EJB 3.0
It is possible for applications to provide an indication that the transactions can be managed by the Container. Such transactions which are not managed through the application’s code but through the container are called Container managed transactions. It is the responsibility of the application developer to specify the transaction demarcation through transactional attributes. This information can be specified either through Annotations or through the configuration file. Note that specifying the transactional metadata through annotations is not available until the version 3.
Transactional Attributes
Container managed transactions are supported through various transactional attributes. The available transactional attributes are as follows
- Required
- Requires New
- Supports
- Not Supported
- Mandatory
- Never
Required
This is the default attribute if the transactional attribute is not specified. This indicates to the container that the annotated business method has to execute within a transaction. More specifically, when there is an active transaction, and if a business method is called from within the active transaction, then the method executes as if it is part of the transaction. This means that the success or the failure of the transaction will be propagated to this transaction. When the caller is not part of a transaction, then a new transaction is started. Consider the following code snippet,
package net.javabeat.articles.ejb.txnmgmt.container.required; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; @Stateless @TransactionManagement(TransactionManagementType.CONTAINER) public class EmployeeDetailBean implements EmployeeDetailLocal { @TransactionAttribute(TransactionAttributeType.REQUIRED) public void createEmployeeDetail() { } }
In the above enterprise bean definition, we have annotated the method createEmployeeDetail() with the ‘Required’ annotation. This business method will be called from the EmployeeBean which is defined below.
package net.javabeat.articles.ejb.txnmgmt.container.required; import javax.ejb.EJB; import javax.ejb.Stateless; @Stateless public class EmployeeBean implements EmployeeLocal { @EJB private EmployeeDetailLocal employeeDetailBean; public void createEmployee() { // Create employee here employeeDetailBean.createEmployeeDetail(); } }
As we can see in the createEmployee() method, the employee object is expected to be created first followed by the creation of employee detail object. Now if there is exception before the return of the business method ‘createEmployee()’ then the employee detail object won’t be created.
Requires New
The transactional attribute ‘Requires New’ will also start a new transaction irrespective of the fact that the caller is in active transaction or not. This attribute can be applied to business methods where the result of the calling transaction is not dependent on the business method that is annotated with ‘Requires New’.
package net.javabeat.articles.ejb.txnmgmt.container.requiresnew; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; @Stateless @TransactionManagement(TransactionManagementType.CONTAINER) public class DepartmentBean implements DepartmentBeanRemote { @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void createDepartment() { } }
Considering the above example, we have a business method that creates a department object and the method is annotated with the transactional attribute ‘Requires New’. Now consider the below code,
package net.javabeat.articles.ejb.txnmgmt.container.requiresnew; import javax.ejb.EJB; import javax.ejb.Stateless; @Stateless public class EmployeeBean implements EmployeeBeanRemote { @EJB private DepartmentBeanRemote departmentBean; public void createEmployee() { // Create employee object here departmentBean.createDepartment(); // Assign the newly created department object to the employee object } }
Here after creating the employee object, we call the enterprise bean for creating a department. Let us assume that we a creating a new employee object and during the course of creation, we also want to create a new department object and assign it to the employee object. Now imagine a transactional failure before the return of the method createEmployee(), in which case, the creation of the department won’t be rolled back because the department creation process is in a separate transaction. This also means that when we create a different employee object we can assign this employee object to the already created department object.
Supports
The transactional attribute ‘Supports’ defines that the transactional mode has to be propagated from the caller to the business method that is annotated with ‘Supports’. This means that if the caller is in an active transaction, then the business method will also execute as part of the active transaction. This means that a failure in the business method will revert the caller’s transaction also. If the caller is not part of the transactional context, then the business method will also execute in a non-transactional context.
Not Supported
This transactional attribute can be used for scenarios where a part of the business operation shouldn’t be executed in a transactional context at all. If the caller is part of the transaction, then the caller’s transaction is suspended and resumed once the execution of the business method that is annotated with ‘Not Supports’ is completed. If the caller is not part of any transaction, then also the business method will execute outside the transactional context.
package net.javabeat.articles.ejb.txnmgmt.container.requiresnew.notsupported; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; @Stateless @TransactionManagement(TransactionManagementType.CONTAINER) public class MailSenderBean implements MailSenderLocal { @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public void sendMail() { } }
In the above example, we have modeled a simple sessionbean that sends a mail. Let us assume that this bean will be used as part of some user registration process. That is, once the user is registered, the application will try to send a mail by calling this enterprise bean. Because the operation of sending a mail to the customer can’t be part of a transaction, the method is annotated with ‘Not Supported’. Have a look at the caller’s code.
package net.javabeat.articles.ejb.txnmgmt.container.requiresnew.notsupported; import javax.ejb.EJB; import javax.ejb.Stateless; @Stateless public class UserRegistrationBean implements UserRegistrationLocal { @EJB private MailSenderLocal mailSenderBean; public void registerUser() { // Do user registration here mailSenderBean.sendMail(); } }
Mandatory
The transactional attribute ‘Mandatory’ can be used when we wanted to make sure that some business method has to be executed as part of a transaction. If the caller’s code is not part of the transaction, then an exception will be thrown. Have a look at the below code.
package net.javabeat.articles.ejb.txnmgmt.container.mandatory; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; @Stateless @TransactionManagement(TransactionManagementType.CONTAINER) public class MoneyTransferBean implements MoneyTransferLocal { @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void transferMoney() { deductMoneyFromSource(); addMoneyToDestination(); } @TransactionAttribute(TransactionAttributeType.MANDATORY) public void deductMoneyFromSource() { } @TransactionAttribute(TransactionAttributeType.MANDATORY) public void addMoneyToDestination() { } }
We have defined three business methods ‘transferMoney’, ‘deductMoneyFromSource’ and ‘addMoneyToDestination’. If we assume that the business method ‘deductMoneyFromSource’ and ‘addMoneyToDestination’ should be part of some transactional method ‘transferMoney’, then these methods have to be annotated with ‘Mandatory’ annotation. This ensures that the business methods ‘deductMoneyFromSource’ and ‘addMoneyToDestination’ cannot be and shouldn’t be executed from a non-transactional environmental context.
Never
This is a rarely used transactional attribute as an exception will be thrown if a caller, as part of an active transaction, executes a business method that is annotated with ‘Never’.
package net.javabeat.articles.ejb.txnmgmt.container.never; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; @Stateless @TransactionManagement(TransactionManagementType.CONTAINER) public class DataLoaderBean implements DataLoaderLocal { @TransactionAttribute(TransactionAttributeType.NEVER) public void loadDataFromXml(String xmlFilename) { } @TransactionAttribute(TransactionAttributeType.NEVER) public void loadDataFromFlatFile(String filename) { } }
In the above example, we have business methods for loading data from a non-transactional data resource such as the file system. Hence we have given the transactional attribute as ‘Never’.
Bean Managed transactions in EJB 3.0
Now that we have seen the advantages and the usage of CMT, let’s see where and how to use Bean Managed Transactions. Even though it is quite uncommon, still there are scenarios where customizations with respect to transaction handling might be required at the application level. The level of customization include when to begin a transaction in a business method, when to commit a transaction by defining a successful scenario and when to rollback a transaction for a failure scenario. For example consider the sample code,
package net.javabeat.articles.ejb.txnmgmt.bean; import javax.annotation.Resource; import javax.ejb.Stateless; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; import javax.transaction.UserTransaction; @TransactionManagement(value=TransactionManagementType.BEAN) @Stateless public class BillPaymentBeanBean implements BillPaymentBeanLocal { @Resource private UserTransaction userTransaction; public void payBill() throws Exception{ try{ userTransaction.begin(); provideBillDetailsInfo(); identifyCustomerAccount(); makeBillPayment(); userTransaction.commit(); }catch (IncorrectBillDetailsException exception){ userTransaction.rollback(); }catch (InvalidCustomerAccountException exception){ userTransaction.rollback(); }catch (PaymentException exception){ userTransaction.rollback(); } } private void identifyCustomerAccount() throws InvalidCustomerAccountException { } private void makeBillPayment() throws PaymentException{ } private void provideBillDetailsInfo() throws IncorrectBillDetailsException{ } }
The first obvious thing to be noted in BMT is that we have to use @TransactionManagement(BEAN) to instruct the container that we are using Bean managed transactions for this enterprise bean. The above example shows how to use BMT with the help of UserTransaction interface. UserTransaction provides a single entry point for managing bean managed transactions and to obtain a valid reference to this interface, the annotation @Resource can be used. This makes sure that the container populates the UserTransaction reference and makes it available. To signal the logical beginning of a transaction, the method begin() can be used. Similarly there are commit() and rollback() signaling that the transaction is successful or failure respectively. Note that in the above example case, whenever we encounter a exception scenario, we indicate that the transaction is a failure by calling the rollback() method. The code snippet for the related exception classes are given below.
package net.javabeat.articles.ejb.txnmgmt.bean; public class IncorrectBillDetailsException extends Exception{ } package net.javabeat.articles.ejb.txnmgmt.bean; public class InvalidCustomerAccountException extends Exception { } package net.javabeat.articles.ejb.txnmgmt.bean; public class PaymentException extends Exception{ }
Handling Exceptions in EJB 3.0
It is important to understand the effect of exceptions when dealing with transactional business methods. In the context of Enterprise beans, exceptions can be either classified as System Exception or Application Exception.
System Exception
The default behaviour of the EJB Container is to rollback the transaction whenever a System exception occurs. Any Exception that is a subclass of RuntimeException or RemoteException will be classified and treated as a System exception. This is the default exception handling when the transaction is managed by the container. When a system error is encountered, the calling client will always perceive that exception as a instance of EJBException or RemoteException. However in the case of Bean managed transactions, it is upto the application as how to handle the system exception, though it is considered as a bad programming practice to catch a system exception and not performing a rollback. For example, consider the following code snippet
@Resource private UserTransaction transaction; public void someBizMethod(){ try{ transaction.begin(); }catch (NullPointerException npe){ transaction.commit(); } }
In the above exception, even through NullPointerException is a system exception (because NullPointerException is an instance of RuntimeException), we are making a commit by calling the transaction’s commit() method.
Application Exception
Application exceptions are generally thrown when the attempt is made to execute a business method results in an error because during the course of the execution it is identified that some business logic went wrong. For example, while performing money transfer between two accounts it is mandatory that sufficient funds have to be present in the source account. An application error can be thrown during the execution of this business method because of insufficient funds. By default when an application error is thrown, the container won’t rollback the transaction as opposed to System exceptions. Also the exception will be reached its client in its regular form, i.e unlike System exceptions, where the source of the exception will be wrapped as either EJBException or RemoteException.
There can be cases where we want to make the transaction rollback for an application exception. In the case of a Bean managed transaction, this scenario is straight-forward, as the application has the control over the UserTransaction. Rolling the transaction would be as simple to call the method rollback(). However, in the case of the Container managed transactions, the situation becomes quite tricky and the annotation @ApplicationException comes to the rescue. For example, let us consider that in the example of money transfer, if sufficient amount is not available in the source account, then we want to throw a customized exception called InsufficientFundsException and also to rollback the transaction.
@ApplicationException(rollback=true) public class InsufficientFundsException extends Exception{ public InsufficientFundsException(String message){ } }
In the above code snippet, we have created a customized exception along with the annotation Application Exception with the attribute rollback set to true. This ensures that for a business method, that declares this exception at the throws clause, when this exception is encountered during the execution of the business operation, the container will request for a transaction rollback.
Persistence Context and Entity Manager
Closely associated with EJB transactions are Entity Manager and Persistence Contexts. Entity Manager is an interface for managing entites whereas Persistence Context is an annotation that can be applied on Entity Manager instances. The annotation has name, persistence unit name and type. The persistence unit name, if specified has to match the unit name that is defined in the persistence.xml file. Persistence context can either be transaction scoped or extended scoped. If the persistence context operates in transaction scope, then it means that the entities that are associated with the persistence context have the life-time equal to that of the transaction. That is, when the transaction ends, any changes done to the entities wont get notified to the persistence context. However, in the case of the extended persistence context, the entities will be attached to the persistence context even after the completion of the transaction. The entities will be detached from the persistence context only when the method close() is called on the Entity Manager object.
Consider the following piece of code,
package net.javabeat.articles.ejb.transactions.application; import java.util.List; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @Stateless public class ApplicationFacade implements ApplicationFacadeRemote { @PersistenceContext private EntityManager em; public void create(Application application) { em.persist(application); } public void edit(Application application) { em.merge(application); } public void remove(Application application) { em.remove(em.merge(application)); } public Application find(Object id) { return em.find(Application.class, id); } public List findAll() { return em.createQuery("select object(o) from Application as o").getResultList(); } }
Note that the entity manager reference is injected by the container as it is annotated with @PersistenceContext annotation. If the persistent unit name is not specified as part of the annotation, then by default, the file name persistence.xml will be looked up for finding the persistence name. The contents of the persistence.xml is given below,
<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="Application-ejbPU" transaction-type="JTA"> <provider>oracle.toplink.essentials.PersistenceProvider</provider> <jta-data-source>new</jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="toplink.ddl-generation" value="drop-and-create-tables"/> </properties> </persistence-unit> </persistence>
Conclusion
This article started by exploring the various techniques of managing transactions in an EJB environment – namely the Container Managed transactions and Bean managed transactions. The various transactional attributes that are applicable for contained managed transactions are given a healthier discussion under the section ‘Transactional attributes’. Also for easier understanding, many sample code snippets were presented for illustration. Then the article went on with discussing the usage the Bean managed transactions. Because it is essential to understand the impact of exception handling with respect to transactions, the final section of the article explained the exception handling mechanisms for System Exceptions and Application Exceptions.
also read: