Using transactional and non-transactional Resources simultaneously

Problem:

  • Bean performs operations on transactional Resource, for instance database connection, and on non-transactional Resource, for instance LDAP connection
  • Bean exposes a business method that uses both database connection and LDAP connection
  • Operations on database connection and LDAP connection must both succeed or be rolled back

What is the bast way to achieve it?

Transactional Resource is a transactional Managed Resource i.e. it integrates with JTA transactions. Non-transactional Resource is any Resource that does not support transactions or supports only local transactions.

Case 1. The business method can use isolated transaction. I.e. client’s transaction does not propagate and the business method is not a part of a larger transactional process.

Solution:

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class ABean {
   @Resource
   private UserTransaction tx;
   ...
   public void businessMethod(){
      //initialization
      dbConnection = ...;
      ldapConnection = ...;

      tx.begin();
      try {
         //database operations in an abbreviation
         dbConnection.executeQuery(...);
      } catch (SQLException e) {
         tx.rollback();
         throw new RuntimeException(e);
      }
      try {
         //LDAP operation in an abbreviation
         ldapConnection.executeQuery(...);
      } catch (LdapException e) {
         tx.rollback();
         throw new RuntimeException(e);
      }
      try {
         //usually commit succeeds
         //but if it fails then ldap operation should be rolled back
         tx.commit();
      } catch (Exception e) {
         //rollback of LDAP operation
         //is just a performance of the opposite operation
         ldapConnection.executeQuery(...);
      }
   }
}

Description:

  • It can be any type of Session Bean
  • Exceptions handling is omitted or simplified, operations on connections are schematic and simplified, resources clean up is omitted, all for brevity
  • Bean Transaction Management gives greater control over a transaction, if commit fails we can perform more non-transactional operation as a failure handling
  • Usually commit rarely fails

Algorithm:

  1. Initialize connections
  2. Start a transaction
  3. Perform transactional database operations
    1. If any operation fails then just rollback the transaction
  4. Perform non-transactional LDAP operation
    1. If operation fails then just rollback the transaction
  5. Commit the transaction
    1. If commit fails then LDAP operation is rolled back manually by performing the opposite operation

Case 2. The business method cannot use isolated transaction. I.e. bean must be ready to propagate client’s transaction and the business method is intended to be a part of a larger transactional process.

We want to propagate a client’s transaction thus we cannot use Bean Transaction Management. The problem is handling of commit failure. If commit fails then LDAP operation can be rolled back only manually. If application does not require high consistency, i.e. excessive LDAP operations are accepted, then we can just ignore commit failure’s handling. Assume that an application must ensure high consistency. Then we need to control Container Managed Transaction. The only way to achieve it is to use Stateful Session Bean with transaction listening methods.

@Stateful
public class ABean {
   @Resource
   private SessionContext ctx;
   ...
   public void businessMethod(){
      try {
         //database operations in an abbreviation
         dbConnection.executeQuery(...);
      } catch (SQLException e) {
         ctx.setRollbackOnly();
         return;
      }
      try {
         //LDAP operation in an abbreviation
         ldapConnection.executeQuery(...);
      } catch (LdapException e) {
         ctx.setRollbackOnly();
         return;
      }
   }
   @AfterCompletion
   private void afterCompletion(boolean success) {
      if (success)
         return;
      //rollback of LDAP operation
      //is just a performance of the opposite operation 
      ldapConnection.executeQuery(...);
   }
}

Resources initialization and cleanup is omitted.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: