6.1.8. Transaction Control Handler

This handler realizes transparent transactions in subsequent processes using resources corresponding to transactions such as databases and message queues.

For transaction details, see Transaction Management .

This handler performs the following process.

  • Begin a transaction
  • End a transaction (commit or rollback)
  • Callback at the end of the transaction

The process flow is as follows.

../../../../_images/flow9.png

6.1.8.2. Module list

<dependency>
  <groupId>com.nablarch.framework</groupId>
  <artifactId>nablarch-core-transaction</artifactId>
</dependency>

<!-- Only to control transactions to the database -->
<dependency>
  <groupId>com.nablarch.framework</groupId>
  <artifactId>nablarch-core-jdbc</artifactId>
</dependency>

<!-- Only when executing an optional process at the end of the transaction -->
<dependency>
  <groupId>com.nablarch.framework</groupId>
  <artifactId>nablarch-core</artifactId>
</dependency>

6.1.8.3. Constraints

Place after Database Connection Management Handler
When controlling a transaction in a database, a database connection for transaction management must exist in the thread. Therefore, this handler must be placed after the Database Connection Management Handler .

6.1.8.4. Configure the transaction control target

This handler uses the factory class ( TransactionFactory implementation class) configured in the transactionFactory property to obtain the control target of the transaction and manage it on the thread.

When managing on a thread, configure a name to identify the transaction. By default, transaction is used but to use a different name, configure the name in the transactionName . When using multiple transactions , it is required to set the value to the transactionName property.

Tip

To perform transaction control on the database configured with Database Connection Management Handler , configure the same value configured in DbConnectionManagementHandler#connectionName to the transactionName property.

If a value is not configured in DbConnectionManagementHandler#connectionName , then the configuration of transactionName can be omitted.

Configure the handler by referring to the configuration file example given below.

<!-- Transaction control handler -->
<component class="nablarch.common.handler.TransactionManagementHandler">
  <property name="transactionFactory" ref="databaseTransactionFactory" />
  <property name="transactionName" value="name" />
</component>

<!-- When performing transaction control on the database, configure JdbcTransactionFactory -->
<component name="databaseTransactionFactory"
    class="nablarch.core.db.transaction.JdbcTransactionFactory">
  <!-- Property configuration is omitted -->
</component>

6.1.8.5. Commit a transaction in the case of specific exception

All errors and exceptions are subject to rollback in the default operation of this handler, but you may want to commit transaction depending on the contents of the exception that was thrown.

In this case, configure the exception class of the commit target for the transactionCommitExceptions property. The subclass of the configured exception class will also be a target for commit.

A configuration example is shown below.

<component class="nablarch.common.handler.TransactionManagementHandler">
  <!-- Configure the exception class of commit target in transactionCommitExceptions property with FQCN. -->
  <property name="transactionCommitExceptions">
    <list>
      <!-- example.TransactionCommitException is targeted for commit -->
      <value>example.TransactionCommitException</value>
    </list>
  </property>
</component>

6.1.8.6. Execute optional processing at the end of the transaction

This handler performs the callback process when the transaction ends (commit or rollback).

The process to be called back is the handler that implements TransactionEventCallback among the handlers configured after this handler. If multiple handlers implement TransactionEventCallback , then the callback process is performed sequentially from the handler that has been configured earlier.

When rolling back a transaction, the callback process is executed after roll back. Therefore, the callback process is performed in a new transaction and is committed when the callback has completed successfully.

Important

Note that if multiple handlers have implemented the callback process and an error or exception occurs during the callback process, the callback process for the remaining handlers is not performed.

An example is shown below.

Creating a handler that performs callback process

Create a handler that implements TransactionEventCallback as shown in the following implementation example.

Implement the callback process at the time of transaction commit in transactionNormalEnd , and implement the callback process at the time of transaction rollback in transactionAbnormalEnd.

public static class SampleHandler
    implements Handler<Object, Object>, TransactionEventCallback<Object> {

  @Override
  public Object handle(Object o, ExecutionContext context) {
    // Implement handler processing
    return context.handleNext(o);
  }

  @Override
  public void transactionNormalEnd(Object o, ExecutionContext ctx) {
    // Implement callback process when committing a transaction
  }

  @Override
  public void transactionAbnormalEnd(Throwable e, Object o, ExecutionContext ctx) {
    // Implement callback process during transaction rollback
  }
}
Build a handler queue

Configure the handler that implements callback process in the subsequent handler of this handler as follows.

<list name="handlerQueue">
  <!-- Transaction control handler -->
  <component class="nablarch.common.handler.TransactionManagementHandler">
    <!-- Configuration of property is omitted -->
  </component>

  <!-- Handler that implements callback process -->
  <component class="sample.SampleHandler" />
</list>

6.1.8.7. Using multiple transactions in an application

There may be cases where one application requires multiple transaction controls. In this case, multiple handlers are configured on the handler queue to manage the situation.

A configuration example for controlling transactions of multiple database connections is shown below.

<!-- Configure default database connection -->
<component name="defaultDatabaseHandler"
    class="nablarch.common.handler.DbConnectionManagementHandler">

  <property name="connectionFactory" ref="connectionFactory" />

</component>

<!-- Register a database connection with the name userAccessLog -->
<component name="userAccessLogDatabaseHandler"
    class="nablarch.common.handler.DbConnectionManagementHandler">

  <property name="connectionFactory" ref="userAccessLogConnectionFactory" />
  <property name="connectionName" value="userAccessLog" />

</component>

<!-- Configure transaction control for the default database connection -->
<component name="defaultTransactionHandler"
    class="nablarch.common.handler.TransactionManagementHandler">

  <property name="transactionFactory" ref="databaseTransactionFactory" />

</component>

<!-- Transaction control configuration for the database connection userAccessLog -->
<component name="userAccessLogTransactionHandler"
    class="nablarch.common.handler.TransactionManagementHandler">

  <property name="transactionFactory" ref="databaseTransactionFactory" />
  <property name="transactionName" value="userAccessLog" />

</component>

An example where the above handler is configured in the handler queue is shown.

<!-- Handlers other than database and transaction control are omitted -->

<list name="handlerQueue">
  <!-- Connection to default database and transaction control -->
  <component-ref name="defaultDatabaseHandler" />
  <component-ref name="defaultTransactionHandler" />

  <!-- Connection and transaction control of userAccessLog database -->
  <component-ref name="userAccessLogDatabaseHandler" />
  <component-ref name="userAccessLogTransactionHandler" />
</list>