Container-managed transactions

Because EJB methods are transactional by default, we run into an interesting dilemma when an EJB method is invoked from client code that is already in a transaction. How should the EJB container behave? Should it suspend the client transaction, execute its method in a new transaction, and then resume the client transaction? Should it not create a new transaction and execute its method as part of the client transaction? Should it throw an exception?

By default, if an EJB method is invoked by client code that is already in a transaction, the EJB container will simply execute the session bean method as part of the client transaction. If this is not the behavior we need, we can change it by decorating the method with the @TransactionAttribute annotation. This annotation has a value attribute that determines how the EJB container will behave when the session bean method is invoked within an existing transaction and when it is invoked outside any transactions. The value of the value attribute is typically a constant defined in the javax.ejb.TransactionAttributeType enum.

The following table lists the possible values for the @TransactionAttribute annotation:

Values

Description

TransactionAttributeType.MANDATORY

Forces the method to be invoked as part of a client transaction. If the method is called outside any transactions, it will throw a TransactionRequiredException.

TransactionAttributeType.NEVER

The method is never executed in a transaction. If the method is invoked as part of a client transaction, it will throw a RemoteException. No transaction is created if the method is not invoked inside a client transaction.

TransactionAttributeType.NOT_SUPPORTED

If the method is invoked as part of a client transaction, the client transaction is suspended and the method is executed outside any transaction; after the method completes, the client transaction is resumed. No transaction is created if the method is not invoked inside a client transaction.

TransactionAttributeType.REQUIRED

If the method is invoked as part of a client transaction, the method is executed as part of this transaction. If the method is invoked outside any transaction, a new transaction is created for the method. This is the default behavior.

TransactionAttributeType.REQUIRES_NEW

If the method is invoked as part of a client transaction, this transaction is suspended, and a new transaction is created for the method. Once the method completes, the client transaction is resumed. If the method is called outside any transactions, a new transaction is created for the method.

TransactionAttributeType.SUPPORTS

If the method is invoked as part of a client transaction, it is executed as part of this transaction. If the method is invoked outside a transaction, no new transaction is created for the method.

 

Although the default transaction attribute is reasonable in most cases, it is good to be able to override this default if necessary. For example, as transactions have a performance impact, being able to turn off transactions for a method that does not need them is beneficial. For a case like this, we would decorate our method as illustrated in the following code snippet:

@TransactionAttribute(value=TransactionAttributeType.NEVER)  
public void doitAsFastAsPossible() 
{ 
  //performance critical code goes here. 
} 

Other transaction attribute types can be declared by annotating the methods with the corresponding constant in the TransactionAttributeType enum.

If we wish to override the default transaction attribute consistently across all methods in a session bean, we can decorate the session bean class with the @TransactionAttribute annotation; the value of its value attribute will be applied to every method in the session bean.

Container-managed transactions are automatically rolled back whenever an exception is thrown inside an EJB method. Additionally, we can programmatically roll back a container-managed transaction by invoking the setRollbackOnly() method on an instance of javax.ejb.EJBContext corresponding to the session bean in question. The following example is a new version of the session bean we saw earlier in this chapter, modified to roll back transactions if necessary:

package net.ensode.javaeebook; 
 
//imports omitted 
 
@Stateless 
public class CustomerDaoRollbackBean implements CustomerDaoRollback 
{ 
  @Resource     
  private EJBContext ejbContext; 
 
  @PersistenceContext 
  private EntityManager entityManager; 
 
 
 
 
 
 
  public void saveNewCustomer(Customer customer) 
  { 
    if (customer == null || customer.getCustomerId() != null) 
    { 
      ejbContext.setRollbackOnly(); 
    } 
    else 
    { 
      customer.setCustomerId(getNewCustomerId()); 
      entityManager.persist(customer); 
    } 
  } 
 
  public void updateCustomer(Customer customer) 
  { 
    if (customer == null || customer.getCustomerId() == null) 
    { 
      ejbContext.setRollbackOnly(); 
    } 
    else 
    { 
      entityManager.merge(customer); 
    } 
  } 
//Additional method omitted for brevity. 
 
} 

In this version of the DAO session bean, we deleted the saveCustomer() method and made the saveNewCustomer() and updateCustomer() methods public. Each of these methods now checks to see if the customerId field is set correctly for the operation we are trying to perform (null for inserts and not null for updates). It also checks to make sure the object to be persisted is not null. If any of the checks results in invalid data, the method simply rolls back the transaction by invoking the setRollBackOnly() method on the injected instance of EJBContext and does not update the database.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.217.17