5

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.

Alexander Camperov
  • 393
  • 2
  • 5
  • 11

2 Answers2

2

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.

Community
  • 1
  • 1
Boris Treukhov
  • 17,493
  • 9
  • 70
  • 91
  • 1
    I expect this because my configuration class implements TransactionManagementConfigurer and the overriden method annotationDrivenTransactionManager returns defTransactionManager() – Alexander Camperov Aug 06 '12 at 13:11
  • @AlexanderCamperov is it a web application? – Boris Treukhov Aug 06 '12 at 13:13
  • Have you checked if `@Transactional()` works on the exactly the same beans you where you expect `@Transactional("secondTM")` to work? – Boris Treukhov Aug 06 '12 at 13:20
  • I cannot do this, they meant to work with different datasources and different entities. Actually they worked fine before I started migrating my project from xml configuration to annotation configuration. – Alexander Camperov Aug 06 '12 at 13:26
  • Also there's a little chance that the beans, where @@Transactional does not work, are actually residing in another context where AOP interceptors are not declared. For example if your transaction configuration works in root app context, but the @@Transactional annotation is declared on the servlet context beans - e.g. if they were accidentally picked by autoscanning and created in servlet context. – Boris Treukhov Aug 06 '12 at 13:37
1

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 { ... }
Sleeper9
  • 1,707
  • 1
  • 19
  • 26