Friday 4 September 2009

The moment of understanding the JTA transactions



Transactions
A transaction is a grouping of tasks that must be processed as an inseparable unit. If any of the tasks fail, the transaction fails as well. Transactions must be guaranteeing a degree of reliability, robustness and ACID properties (atomicity, consistency, isolation and durability). A successful transaction is committed, meaning its results are made permanent, whereas a failed transaction is rolled back, as if it never happened.
In enterprise transaction management, the component that takes care of transactions for a particular resource is called a resource manager. A transaction that uses a single resource is called a local transaction. However, many enterprise applications use more than one resource. The component that coordinates a transaction over multiple distributed resources is called transaction manager. A Transaction that uses multiple resources is called global transaction.





Many applications will consist of one or several enterprise beans that all use a single resource manager (typically a relational database management system). The EJB container can make use of resource manager local transactions as an optimization technique for enterprise beans for which distributed transactions are not needed. A resource manager local transaction does not involve control or coordination by an external transaction manager. The container’s use of local transactions as an optimization technique for enterprise beans with either container-managed transaction demarcation or bean-managed transaction demarcation is not visible to the enterprise beans.

Property
Local
Global transaction
Number of resources
One
Multiple
Coordinator
Resource Manager
Transaction Manager
Commit protocol
Single-phase
Two-phase


The are two ways to use transactions in EJB. The first is to declaratively manage transactions through container-managed transactions (CMT); this can be done through annotations or the deployment descriptor. On the other hand, bean-managed transaction (BMT) requires explicitly manage transactions programmatically.
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 server provider. The EJB container and server implement the necessary low-level transaction protocols, such as the two-phase commit protocol between a transaction manager and a database system or messaging provider, transaction context propagation, and distributed two-phase commit.
Note: The Enterprise JavaBeans architecture supports flat transactions. A flat transaction cannot have any child (nested) transactions.

Specification of a Bean’s Transaction Management Type
By default, a session bean or message-driven bean has container managed transaction demarcation if the transaction management type is not specified. The Bean Provider of a session bean or a message-driven bean can use the TransactionManagement annotation to declare whether the session bean or message-driven bean uses bean-managed or container-managed transaction demarcation. The value of the TransactionManagement annotation is either CONTAINER or BEAN. The TransactionManagement annotation is applied to the enterprise bean class.
Alternatively, the Bean Provider can use the transaction-type deployment descriptor element to specify the bean’s transaction management type. If the deployment descriptor is used, it is only necessary to explicitly specify the bean’s transaction management type if bean-managed transaction is used.


Container-Managed Transaction Demarcation
The container is responsible for providing the transaction demarcation for the session beans, message-driven beans declared with container-managed transaction demarcation, entity beans with bean-managed persistence, and for EJB 2.1 and EJB 1.1 entity beans with container-managed persistence. For these enterprise beans, the container must demarcate transactions as specified by the transaction attribute values specified using metadata annotations in the bean class or specified in the deployment descriptor.
Transaction boundaries in declarative transactions are always marked by the start and end of EJB business method.
The Bean Provider of an enterprise bean with container-managed transaction demarcation may specify the transaction attributes for the enterprise bean’s methods. By default, if a TransactionAttribute annotation is not specified for a method of an enterprise bean with container-managed transaction demarcation, the value of the transaction attribute for the method is defined to be REQUIRED.
A transaction attribute is a value associated with each of the following methods
a method of a bean’s business interface
a message listener method of a message-driven bean
a timeout callback method
a stateless session bean’s web service endpoint method
for beans written to the EJB 2.1 and earlier client view, a method of a session or entity bean’s home or component interface
The next table shows the effects transaction attributes on EJB methods:

Transaction Attribute
Caller’s Transaction
Effect
REQUIRED
No
Container creates a new transaction.
Yes
Method joins the caller’s transaction.
REQUIRES_NEW
No
Container creates a new transaction.
Yes
Container creates a new transaction and the caller’s transaction is suspended.
SUPPORT
No
No transaction is used.
Yes
Method joins the caller’s transaction.
MANDATORY
No
javax.ejb.EJBTransactoinRequiredException is thrown.
Yes
Method joins the caller’s transaction.
NOT_SUPPORTED
No
No Transaction is used.
Yes
The caller’s transaction is suspended and the method is called without a transaction.
NEVER
No
No Transaction is used.
Yes
javax.ejb.EJBException is thrown.


Only the NOT_SUPPORTED and REQUIRED transaction attributes may be used for message-driven bean message listener methods. The use of the other transaction attributes is not meaningful for message-driven bean message listener methods because there is no pre-existing client transaction context (REQUIRES_NEW, SUPPORTS) and no client to handle exceptions (MANDATORY, NEVER).
Messaging systems may differ in quality of service with regard to reliability and transactionality of the dequeuing of messages.
The requirements for JMS are as follows:
A transaction must be started before the dequeuing of the JMS message and, hence, before the invocation of the message-driven bean’s onMessage method. The resource manager associated with the arriving message is enlisted with the transaction as well as all the resource managers accessed by the onMessage method within the transaction. If the onMessage method invokes other enterprise beans, the container passes the transaction context with the invocation.
The transaction is committed when the onMessage method has completed. If the onMessage method does not successfully complete or the transaction is rolled back, message redelivery semantics apply.


Example 1 – CMT SLSB

@Stateless
@Local(value=SubscriberService.class)
@LocalBinding(jndiBinding="uk.co.test.facade.SubscriberService")
@TransactionManagement(TransactionManagementType.CONTAINER)
public class SubscriberSessionFacade implements SubscriberService {
         
          @PersistenceContext
          private EntityManager em;
         
          private RMSubscriberApplicationService subscriberApplicationService;
         
          private RMServiceApplicationService serviceApplicationService;
         
          private RMNetworkApplicationService networkApplicationService;
         
          @PostConstruct
          public void init(){
                  
                   subscriberApplicationService = new RMSubscriberApplicationService(em);
                   serviceApplicationService = new RMServiceApplicationService(em);
                   networkApplicationService = new RMNetworkApplicationService(em);
         
          }
          public Subscriber createSubscriber(Subscriber entity) {
                   return subscriberApplicationService.create(entity);
          }
          public Subscriber findSubscriberById(long id) {
                   return subscriberApplicationService.findById(id, Subscriber.class);
          }
          public int getSubscriberCount(SearchSubscriberCriteria searchCriteria) {
                   return subscriberApplicationService.getSubscriberCount(searchCriteria);
          }
          public List searchSubscriber(
                             SearchSubscriberCriteria searchCriteria, int startRow, int pageSize) {
                  return subscriberApplicationService.searchSubscriber(searchCriteria, startRow, pageSize);
          }
          public Subscriber updateSubscriber(Subscriber entity) {
                    return subscriberApplicationService.update(entity);
          }
          public List findAllNetwork() {
                   return networkApplicationService.findAll();
          }
          public List findAllService() {
                   return serviceApplicationService.findAll();
          }
}



Exception handling in CMT
If the appropriate business conditions arise, a CMT method can ask the container to roll back a transaction as soon as possible. The important thing to note here is that the transaction is not rolledback immediately, but a flag is set for the container to do the actual rollback when it is time to end the transaction.

@Resource
private SessionContext context;
……
Public void doSomething(Customer customer) {
          try {
                   validationCustomer(customer);                  
} catch (SomeException e) {
          context.setRollbackOnly();
}
}

Note: You can invoke setRollbackOnly, getRollbackOnly methods in the case that your method has a REQUIRED, REQUIRED_NEW or MANDATORY transaction attribute. Otherwise the method will throw an IllegalStateException.
EJB 3 makes the job of translating exception into transaction rollback almost transparent using the ApplicationException paradigm.

@ApplicationException(rollback=true)
Public class SomeExceptoin extends Exception {
……
Therefore
Public void doSomething(Customer customer) throws SomeExceptoin {
          validationCustomer(customer);                  
}

The @ApplicationException annotation identifies a Java checked or unchecked exception as an application exception.
In EJB, an application exception is an exception that the client is expected to handle. When thrown, such exceptions are passed directly to the method invoker. By default, all checked exceptions except for java.rmi.RemoteException are assumed to be application exceptions. On the other hand, all exceptions that inherit from either java.rmi.RemoteException or java.lang.RuntimeException are assumed to be systems exceptions(all the exceptions that inherit from java.lang.RuntimeException are unchecked). In EJB, it is not assumed that system exceptions are expected by the client. When encountered, such exceptions are not passed to the client as is but are wrapped in javax.ejb.EJBException instead.
By default, application exceptions do not cause an automatic CMT rollback since the rollback element is defaulted to false. However, setting the element to true tell the container that it should roll back the transaction before the exception is passed on to the client.
If the container detects a system exception, such as ArrayIndexOutBounds or NullPointerException that you didn’t plan for it, it will still roll back the CMT. However, in such cases the container will also assume that the bean is in inconsistent state and will destroy the instance. Because unnecessarily destroying bean instances is costly, you should never deliberately use system execeptions.

Bean-Managed Transaction Demarcation
The greatest strength of CMT is also its greatest weakness. Using CMT, you are limited to having the transaction boundaries set at the beginning and end of business methods and relying on the container to determine when a transaction starts, commits or roll back. BMT on the other hand, allows you to specify exactly these details programmatically, using semantics similar to the JBDC transaction model with which you might already be familiar. However, even in this case, the container helps you by actually creating the physical transaction as well as taking care of a few low-level details. With BMT, you must be much more aware of the underlying JTA transaction API, primarily the javax.transaction.UserTransaction interface.
The container must make the javax.transaction.UserTransaction interface available to
§          Enterprise bean’s business method
§          Message listener method
§          Interceptor method
§          Timeout callback method

via dependency injection into the enterprise bean class or interceptor class, and through lookup via the javax.ejb.EJBContext interface,

@Resource
private SessionContext context;
UserTransaction userTransaction = context.getUserTransaction();

Or

@Resource
UserTransaction  userTransaction;

and in the JNDI naming context under java:comp/UserTransaction.

Context context = new InitialContext();
UserTransaction userTransaction = (UserTransaction) context.lookup(“java:comp/UserTransaction”);



Example 2 – BMT SLSB
@Stateless
@Local(value=OfferTransactionService.class)
@LocalBinding(jndiBinding="uk.co.test.facade.SubscriberService")
@TransactionManagement(TransactionManagementType.BEAN)
public class SubscriberSessionFacade implements SubscriberService{
         
          @PersistenceContext
          private EntityManager em;
         
          @Resource
          UserTransaction userTransaction;
         
          private RMOfferTransactionApplicationService offerTransactionService;
         
          @PostConstruct
          public void init(){
                   offerTransactionService = new RMOfferTransactionApplicationServiceImpl(em);
          }  
          public void processingOfferTransaction(List list) {
                  
                  
                   try {
                             userTransaction.begin();
                  
                             offerTransactionService.validateOfferTransactions(list);
                             offerTransactionService.createOffrTransactions(list);
                  
                             userTransaction.commit();
                            
                             } catch (ValidateOfferTransactionException v) {
                                      userTransaction.rollback();
                             } catch (CreationOfferTransactionException c) {
                                      userTransaction.rollback();
                             }
                            
                   }
          }
When an instance uses the javax.transaction.UserTransaction interface to demarcate a transaction, the container must enlist all the resource managers used by the instance between the begin and commit or rollback—methods with the transaction. When the instance attempts to commit the transaction, the container is responsible for the global coordination of the transaction commit. The container typically relies on a transaction manager that is part of the EJB server to perform the two-phase commit across all the enlisted resource managers. If only a single resource manager is involved in the transaction and the deployment descriptor indicates that connection sharing may be used, the container may use the local transaction optimization.
The enterprise bean with bean-managed transaction demarcation must be a session bean or a message-driven bean. An instance that starts a transaction must complete the transaction before it starts a new transaction.
The container must manage client invocations to an enterprise bean instance with bean-managed transaction demarcation as follows. When a client invokes a business method via one of the enterprise bean’s client view interfaces, the container suspends any transaction that may be associated with the client request. If there is a transaction associated with the instance (this would happen if a stateful session bean instance started the transaction in some previous business method), the container associates the method execution with this transaction. If there are interceptor methods associated with the bean instances, these actions are taken before the interceptor methods are invoked.
A stateful session bean instance may, but is not required to, commit a started transaction before a business method returns. If a transaction has not been completed by the end of a business method, the container retains the association between the transaction and the instance across multiple client calls until the instance eventually completes the transaction.
A stateless session bean instance must commit a transaction before a business method or timeout callback method returns.
A message-driven bean instance must commit a transaction before a message listener method or timeout callback method returns.

Use of JMS APIs in Transactions
The Bean Provider should not make use of the JMS request/reply paradigm (sending of a JMS message, followed by the synchronous receipt of a reply to that message) within a single transaction. Because a JMS message is typically not delivered to its final destination until the transaction commits, the receipt of the reply within the same transaction will not take place.
Because the container manages the transactional enlistment of JMS sessions on behalf of a bean, the parameters of the createSession(boolean transacted, int acknowledgeMode), createQueueSession(boolean transacted, int acknowledgeMode) and createTopicSession( boolean transacted, int acknowledgeMode) methods are ignored. It is recommended that the Bean Provider specify that a session is transacted, but provide 0 for the value of the acknowledgment mode.
The Bean Provider should not use the JMS acknowledge method either within a transaction or within an unspecified transaction context. Message acknowledgment in an unspecified transaction context is handled by the container.

The Optional SessionSynchronization Interface for Stateful Session Beans
A stateful session bean class can optionally implement the javax.ejb.SessionSynchronization interface. This interface provides the session bean instances with transaction synchronization notifications. The instances can use these notifications, for example, to manage database data they may cache within transactions—e.g., if the Java Persistence API is not used.
The afterBegin notification signals a session bean instance that a new transaction has begun. The container invokes this method before the first business method within a transaction (which is not necessarily at the beginning of the transaction). The afterBegin notification is invoked with the transaction context. The instance may do any database work it requires within the scope of the transaction.
The beforeCompletion notification is issued when a session bean instance’s client has completed work on its current transaction but prior to committing the resource managers used by the instance. At this time, the instance should write out any database updates it has cached. The instance can cause the transaction to roll back by invoking the setRollbackOnly method on its session context.
The afterCompletion notification signals that the current transaction has completed. A completion status of true indicates that the transaction has committed. A status of false indicates that a rollback has occurred. Since a session bean instance’s conversational state is not transactional, it may need to manually reset its state if a rollback occurred.
Only a stateful session bean with container-managed transaction demarcation may implement the SessionSynchronization interface. A stateless session bean must not implement the Session-Synchronization interface.
There is no need for a session bean with bean-managed transaction demarcation to rely on the synchronization call backs because the bean is in control of the commit—the bean knows when the transaction is about to be committed and it knows the outcome of the transaction commit.

1 comment:

  1. Nice write up. About REQUIRES_NEW... Given that "An instance that starts a transaction must complete the transaction before it starts a new transaction.", how is REQUIRES_NEW implemented? What does it mean to suspend a caller's transaction? For instance with SQL, does it use a SAVEPOINT? There is no committing the child transaction without committing the parent as well?

    ReplyDelete