Alexander Camperov
Alexander Camperov

Reputation: 393

Multiple transaction managers annotation configuration

I have two transaction managers configured in annotation-based configuration class:

@Configuration
@EnableTransactionManagement
public class DBConfig implements TransactionManagementConfigurer {

//...

@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
    return defTransactionManager();
}

@Bean
@Qualifier("defSessionFactory")
public LocalSessionFactoryBean defSessionFactory() {
    LocalSessionFactoryBean sfb = new LocalSessionFactoryBean();
    sfb.setDataSource(defDataSource());

    Properties props = new Properties();
    //...

    sfb.setHibernateProperties(props);
    sfb.setPackagesToScan("my.package");

    return sfb;
}

@Bean
@Qualifier("defTransactionManager")
public PlatformTransactionManager defTransactionManager() {
    return new HibernateTransactionManager(defSessionFactory().getObject());
}

@Bean
@Qualifier("secondSessionFactory")
public LocalSessionFactoryBean secondSessionFactory() {
    LocalSessionFactoryBean sfb = new LocalSessionFactoryBean();
    sfb.setDataSource(secondDataSource());

    Properties props = new Properties();
    //...

    sfb.setHibernateProperties(props);
    sfb.setPackagesToScan("my.package.subpackage");

    return sfb;
}

@Bean
@Qualifier("secondTM")
public PlatformTransactionManager secondTransactionManager() {
    return new HibernateTransactionManager(secondSessionFactory().getObject());
}
}

My intention is use annotation transactions with two transaction managers. Methonds annotated like this

@Transactional
public void method() {}

should be handled by defTransactionManager

And methods annotated like this

@Transactional("secondTM")
public void anotherMethod() {}

by secondTransactionManager

defTransactionManager works fine but when it comes to anotherMethod() I get:

org.hibernate.HibernateException: No Session found for current thread

When I use programmatic transaction management for anotherMethod (autowire secondSessionFactory, use TransactionTemplate) everything works fine.

Upvotes: 5

Views: 6635

Answers (2)

Sleeper9
Sleeper9

Reputation: 1779

Just in case anyone runs into this problem, I found a solution:

@Configuration
@EnableTransactionManagement
@DependsOn("myTxManager")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements TransactionManagementConfigurer {

@Autowired
private PlatformTransactionManager myTxManager;

...

@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
    return this.myTxManager;
}

In this way, you can use a specific txManager defined in an xml configuration.

In case you want to define the txManager used on service-level, you shall remove the @EnableTransactionManagement annotation from the @Configuration class and specify the txManager in the @Transactional annotations, e.g.

@Service
@Transactional(value="myTxManager", readOnly = true)
public class MyServiceImpl implements MyService { ... }

Upvotes: 1

Boris Treukhov
Boris Treukhov

Reputation: 17774

In case of @EnableTranscationManagement Spring will use by-type lookup, you can provide your own lookup method to a single transaction manager, but it will not work for two tx managers

If you want to check how Spring determines the transaction to execute, you can try to debug the TransactionAspectSupport class. The key methods are setTransactionManagerBeanName and determineTransactionManager.

Upvotes: 3

Related Questions