Supporting Multiple Transaction Managers in Spring

I added Spring JPA to v0.0.4 of my Spring-Data GitHub app and decided to keep the Hibernate persistence logic in place, with Hibernate and Spring JPA both active.

If you’re seeing the error

“org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org…transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: transactionManager1, transactionManager2”

…this post is for you!

Here are some of the configuration details for supporting multiple transaction managers in Spring. The complete source is on GitHub, and make sure you go to the v0.0.4 branch on which this post is based.

First, here’s the layout of the app with both Hibernate and Spring JPA in play. The two Persistence contexts are using the same MySQL backend data and share the same Model objects. Otherwise Hibernate DAO and Services are in a /hbn package, with Spring JPA repositories and services in a /jpa package.

The Configuration

We’re registering two Configuration Classes for our Spring Application Context, one for Hibernate and a second for Spring JPA.  Looking at the Configuration Class Annotations you can see the both are nearly identical. Both are configured to scan the same base package, so the separation of the Hibernate and JPA objects shown above is for separation purposes only. Both contexts can share the same package.

Identifying the Transaction Manager

The key to making multiple transaction managers work is to identify the transaction manager with a Qualifier and specify that transaction manager when used.

We qualify the JpaTransactionManager in SpringJpaConfiguration.

@Bean
@Qualifier(value = "jpaTransactionManager")
public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
	return new JpaTransactionManager(emf);
}

…and the HibernateTransactionManager in SpringHbnConfiguration.

@Bean
@Qualifier(value = "hibernateTransactionManager")
public HibernateTransactionManager hibTransMan() {
	return new HibernateTransactionManager(sessionFactory());
}

Now whenever we use the managers in a Service Implementation, for instance, we specify the Transaction Manager with @Transactional(value = “…”). Be sure to include “value =”.

And that’s pretty much it. We can now instantiate a Transactional Service Bean using its @Service name as usual.

ContactJpaService contactJpaService =
(ContactJpaService) ctx.getBean("jpaContactService");