Monday, September 14, 2015

Configuring Multiple Transaction Managers with @Transactional Annotation

Most of the time Spring applications are working with a single transaction manager, but in some cases applications may have to work with multiple transaction managers.

Suppose an application have to access two databases, "ApplicationDB" and "ApplicatioinDataDB". In here the application should contain two separate data sources and each data source should be accessible via two independent transaction mangers.



In this case, optional value attribute in @Transactional annotation can be used to specify the PlatFormTransactionManager to be used. The value can either be bean name or qualifier value of the transaction manager bean.

Qualifier annotation can be used as follows:

public class ApplicationService {
  
    @Transactional("txGeneral")
    public void setApplicationMetaData(String name) { ... }
  
    @Transactional("txData")
    public void setAppData() { ... }
  }

Transaction manager beans can be defined as follows in the application context:

<tx:annotation-driven/>

  <bean id="transactionManager1" class="org.springframework.jdbc.DataSourceTransactionManager">
    ...
    <qualifier value="txGeneral"/>
  </bean>

  <bean id="transactionManager2" class="org.springframework.jdbc.DataSourceTransactionManager">
    ...
    <qualifier value="txData"/>
  </bean> 

In here both transactioin methods will run under separate transaction managers in separate sessions. The default <tx:annotation-driven> target bean name transactionManager will still be used if no specifically qualified PlatformTransactionManager bean is found.

If the application have to perform cross database transactions, it is better to stick with JTA rather than having separate transaction mangers, because rollback propagation in one transaction running under a transaction manger will not rollback other transaction manager's transaction. Therefore cross database transactions will not be atomic. More about this later....