Spring - How to Use Multiple Transaction Managers in the Same Application

Spring - Is it possible to use multiple transaction managers in the same application?

Where you use a @Transactional annotation, you can specify the transaction manager to use by adding an attribute set to a bean name or qualifier. For example, if your application context defines multiple transaction managers with qualifiers:

<bean id="transactionManager1"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory1" />
<qualifier value="account"/>
</bean>

<bean id="transactionManager2"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory2" />
<qualifier value="businessData"/>
</bean>

You can use the qualifier to specify the transaction manager to use:

public class TransactionalService {

@Transactional("account")
public void setSomethingInAccount() { ... }

@Transactional("businessData")
public void doSomethingInBusinessData() { ... }
}

Multiple Transaction Managers in Spring Boot for different EntityManagers

See if this works:

@Bean
@Primary
@ConfigurationProperties(prefix = "datasource.admin")
public DataSource adminDS() { ... }

@Bean
@Primary
public LocalContainerEntityManagerFactoryBean adminEMF(...) { ... }

@Bean
@Primary
public JpaTransactionManager adminTM(...) { ... }

@Bean
public LocalContainerEntityManagerFactoryBean appEMF(...) { ... }

@Bean
public JpaTransactionManager appTM(...) { ... }

The only change I have made from your configuration is to declare a transaction manager for the admin side explicitly and marked that transaction manager as the default.

Multiple transaction managers - Selecting a one at runtime - Spring

I think you need a Facade. Define an interface and create 2 classes implementing the same interface but with different @Transactional(value = "qatxManager")

Then define one Facade class which keeps 2 implementations (use @Qualifier to distinguish them) The Facade gets the env String and call method of proper bean

Spring multiple transactions with TransactionManager (JMS, database)

Your use case is simple and common. You wish to send a JMS message, wait for that to complete, then commit to the database. This is done on two transactions - one for the JMS message and the other for the database. These transactions both exist in a single transaction context. When you start the JMS transaction, no transaction context will exist, so one will be created. When you start the database transaction, it will join the existing transaction context. These transaction will be synchronized in that the JMS transaction must successfully complete before the database transaction is committed.

Central to this operation is the transaction manager. Looking at the article that you linked, they make many references to the PlatformTransactionManager. In your use case, the PlatformTransactionManager must be a JTA capable transaction manager. A JTA transaction manager will be able to create the transaction context and register and synchronize the transactions.

Note that these are two local transactions, this is not in any way XA or distributed transactions. In this scenario, if the JMS local transaction fails, then the database local transaction will be rolled back. More specifically, it is the transaction context that gets marked as rollback only. If any unhandled exception occurs, then the transaction context is marked rollback only. Any attempts to call commit() on the local transactions will fail with a message stating that the transaction context is rollback only.

Achieving this is platform dependent. For example, if your Spring project is deployed in a WAR file on an application server such as JBoss, then the PlatformTransactionManager will be autowired automatically. If you are using Spring Boot, then most configurations do not even include a transaction manager.

I have a transactional Spring JMS and Camel for Spring Boot here. This is a simple message bridge for IBM MQ. If nothing else, the Spring JMS and annotations and the example for transactional IBM MQ should be useful. Maybe the Camel bits are useful as well.

Note that the pom.xml file contains:

    <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-narayana</artifactId>
</dependency>

This Spring Boot starter will install and configure the Arjuna JTA transaction manager as the PlatformTransactionManager.

In my example, I have:

<logger name="com.arjuna" level="TRACE" additivity="false">
<appender-ref ref="STDOUT" />
</logger>

This provides very nice logging for the Arjuna JTA transaction manager.

Bottom line, get a JTA transaction manager configured as the PlatformTransactionManager. Use this to create a transaction context, and have the two local synchronized transactions in that context.

The example project should be easy to get to run. The logging is very informative.



Related Topics



Leave a reply



Submit