14 - Container-Managed Transactions

Container-Managed Transactions

Container managed transactions are considered the place where the container (JEE Server) controls the boundaries of the transactions, when to begin, when to commit or to rollback.

It simplifies the transaction management process as all the begin, commit and rollback actions are handled by the container and no specific code should be provided to control the process.

Container managed transaction demarcation is the default management type if no type was specified and can be used with any type of enterprise beans, Session beans or Message Driven beans.

The default behavior of this type is to start a new transaction just before the start of method execution and to commit/rollback the transaction just before the method execution ends with one constraint: every method is allowed to contribute in only one transaction, the default behavior can be overridden using transaction attributes.

Example:

package com.ejb3.webservice;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;

@Stateless
@LocalBean
public class ContainerManagedTransactionExample {
   
       public void doAtomicAction() {
        // Operation #1
        // Operation #2
        // Operation #3
    }
}

The example shows a sample Stateless Session Bean that uses a Container-Managed Transactions (default) and the method doAtomicAction will be surrounded with a transaction. The transaction will begin just before the method starts execution and ends (commit/rollback) just before the method execution ends.

The same effect will  be provided if the bean was marked with @TransactionManagement(TransactionManagementType.CONTAINER) annotation:

@Stateless
@LocalBean
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ContainerManagedTransactionExample {

Transaction Attributes

Transaction attributes control the scope and transaction behavior in the marked method. The following attributes are provided by the JEE:

Required

If the called/client (i.e. another bean) already started a transaction, the method will participate in the same transaction scope, if the called didn’t start a transaction before invoking the method, the container will start a new transaction and the method will be added to the transaction scope.

Required attribute is the default attribute that is used if no other attribute was specified for the beans methods.

RequiresNew

With this attribute the container always invokes the method in a new transaction, whether the client has already started a transaction or not. In case the called already started a transaction, the container suspends the transaction, starts another one and adds the method to the new transaction scope. Once the transaction does commit, the container resumes the suspended transaction again.

Mandatory

With this attribute, the client is forced to start a transaction to be able to invoke the method.  In case the caller doesn’t participate in any transaction scope, the container prevents the method invocation and throws a TransactionRequiredException Exception.

NotSupported

This attribute can be used to improve the methods invocation performance as it removes the transaction management overhead from the method invocation. With this attribute, the container suspends the transactions started by the client, if any, and invokes the method in no transaction scope. Once the method invocation is done, the container resumes the client suspended transaction, if any.

Supports

If the enterprise bean’s method is invoked while the client is running within  transaction, then he method executes within the client’s transaction. The container does not start a new transaction before running the method, if the client is not associated with a transaction,

This should be used with caution.  

Never

This attribute means that the method should never run inside a transaction and if the client already started one, the container prevents the method invocation and throws RemoteException exception to the caller thread.

Example on transaction attributes:

package com.ejb3.webservice;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

@Stateless
@LocalBean
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ContainerManagedTransactionExample {

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void method1() {
        // Here the container will always start a new transaction
        // and run the method inside its scope
    }
    @TransactionAttribute(TransactionAttributeType.MANDATORY)
    public void method2() {
        // Here the container will allow only clients that already startd
        // a transaction to call this method
    }
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void method3() {
        // Here the container will make sure that the method
        // will run in no transaction scope and will suspend any
        // transaction started by the client
    }
    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public void method4() {
        // Here the container will allow the method to be called
        // by a client whether the client already has a transaction or not
    }
    @TransactionAttribute(TransactionAttributeType.NEVER)
    public void method5() {
        // Here the container will reject any invocation done by clients already
        // participate in transactions
    }
}

 

Rolling Back a Transaction

Rolling back is the process of cleaning all the changes that are done inside the transaction on the application database. In container managed transaction, there are 2 ways to rollback a transaction -  by throwing a system exception or by calling the method setRollbackOnly of the interface EJBContext. The interface can be set using injection.

In case of throwing application exception, the transaction won’t rollback by the container. For changing this, you can mark the exception with the annotation @ApplicationException(rollback=true). That way the transaction will  rollback in case the exception is thrown inside.

The Check before commit Issue

The check before commit issue or as widely known, the session bean's instance variables synchronization handling, is an issue raised due to the uncontrollable transaction commit.

Let’s check the following bean method:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doAction() {
    insertNewElement();
    updateAnotherElement();
    sendInsertUpdateNotification();
    logAction();
}

Now suppose that the method sendInsertUpdateNotification will call a web service with the following code:

public void handleInsertUpdate() {
    Element e = getNewElement();
    validateElementData(e);
}

Now when the method sendInsertUpdateNotification gets invoked, the web service method handleInsertUpdate will be invoked asynchronously. The web service method will first try to get the newly added element from the database and then validate on that element data.

The following scenario once executed, will produce what can be called a check before commit issue. The web service method is not running in the same transaction scope as the doAction method. So all changes that take place inside the transaction, won’t be visible to the web service method until the transaction does commit. As the commit only takes place just before the doAction method finishes execution, the method handleInsertUpdate will be called before the doAction transaction does commit the changes and will fail to retrieve the newly added element  by the doAction method.

Such issue can be solved using the SessionSynchronization interface. The interface produces 3 methods that can be used to handle operations needed to be invoked just after the transaction starts, just before the transaction ends, and finally after the transaction does commit the changes to the database. Here we can use the last method to send the notification to the web service to check the newly added element, and as this will be after the transaction commit the data, the new element will be visible to the web service method.

Just note that the interface can be used with Stateful Beans and not any other bean.

Example:

package com.ejb3.webservice;

import java.rmi.RemoteException;

import javax.ejb.EJBException;
import javax.ejb.LocalBean;
import javax.ejb.SessionSynchronization;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

@Stateful
@LocalBean
@TransactionManagement(TransactionManagementType.CONTAINER)
public class SessionSynchronizationExample implements SessionSynchronization {

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void doAction() {
        insertNewElement();
        updateAnotherElement();
        logAction();
    }
    @Override
    public void afterBegin() throws EJBException, RemoteException {
    }
    @Override
    public void beforeCompletion() throws EJBException, RemoteException {    
    }
    @Override
    public void afterCompletion(boolean committed) throws EJBException,
            RemoteException {
        if(committed)
            sendInsertUpdateNotification();
    }    
}

Now, as the method will be called after the transaction commit, all data will be persisted permanently in the database and will be visible to other application components.

Like us on Facebook