带有2个事务管理器的@EnableTransactionManagement注释

时间:2011-11-08 12:14:03

标签: java spring spring-3 spring-annotations

我使用@Configuration注释来配置spring而不是xml文件。我正在配置具有不同会话工厂和不同事务管理器的2个数据源。我在这里遇到@EnableTransactionManagement注释的问题。我在其文档中读到了

  

@EnableTransactionManagement更灵活;它将回归到   对类中任何PlatformTransactionManager bean的类型查找   容器。因此,名称可以是" txManager"," transactionManager",或   " tm":它无所谓。

这意味着我给方法提供的任何名称,它总是会搜索返回PlatformTransactionManager对象的方法,而我有2个事务管理器。现在问题是,当我测试这个类时,它给了我错误:

  

org.springframework.beans.factory.NoSuchBeanDefinitionException:没有定义[org.springframework.transaction.PlatformTransactionManager]类型的唯一bean:预期的单个bean但找到了2

我甚至试图拥有2个不同的配置类但是徒劳无功。在xml配置中,情况并非如此。我用两个<tx:annotation-driven transaction-manager="" />标签注册了我的两个交易管理器,它运行正常。但是这里不能用注释做同样的事。

如果我想在Spring注释配置类中配置2个具有2个不同事务管理器的数据源,我该怎么办?

7 个答案:

答案 0 :(得分:33)

在配置类中,使用@EnableTransactionManagement注释。

将此类中的事务管理器定义为:

    @Bean(name="txName")
    public HibernateTransactionManager txName() throws IOException{
        HibernateTransactionManager txName= new HibernateTransactionManager();
        txName.setSessionFactory(...);
        txName.setDataSource(...);
        return txName;
   }

在您的类/方法中执行事务性作业,注释如下:

@Transactional("txName")

@Transactional(value = "txName")

这就是如何将名称限定的事务管理器绑定到您需要的位置。您现在可以拥有任意数量的事务管理器,并根据需要随时使用它。

答案 1 :(得分:8)

万一有人遇到这个问题,我找到了一个解决方案:

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

@Autowired
private PlatformTransactionManager myTxManager;

...

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

通过这种方式,您可以使用xml配置中定义的特定txManager。

如果您想要定义服务级别使用的 txManager ,您应从<{1}}类删除 @EnableTransactionManagement注释在@Configuration注释中指定 txManager ,例如

@Transactional

答案 2 :(得分:5)

来自java doc

  

对于那些希望建立更直接关系的人       @EnableTransactionManagement和要使用的确切事务管理器bean,       可以实现TransactionManagementConfigurer回调接口 - 注意       implements子句和下面的@Override - 注释方法:

您的@Configuration课程需要实施TransactionManagementConfigurer界面 - 实施annotationDrivenTransactionManager,这将返回应该使用的transactionManager的引用。

答案 3 :(得分:1)

我不确定您使用两个TransactionManagers的原因。您可以考虑通过AbstractRoutingDataSource将相同的TransactionManager用于多个数据源。请参考

http://blog.springsource.org/2007/01/23/dynamic-datasource-routing/

了解其使用情况的样本。

答案 4 :(得分:0)

其他一些答案暗示使用两个交易管理器在某种程度上是错误的;但是,Spring的XML配置允许使用在线文档中所述的多个事务管理器(如下所示)。不幸的是,似乎没有办法让@EnableTransactionManagement注释以类似的方式工作。因此,我只需使用@ImportResource注释来加载包含<tx:annotation-driven/>行的XML文件。这允许您为大多数事情获取Java配置,但仍然使用@Transactional和可选的事务管理器限定符。

http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/transaction.html

  

大多数Spring应用程序只需要一个事务管理器,但在某些情况下,您可能需要在单个应用程序中使用多个独立的事务管理器。 @Transactional注释的value属性可用于选择性地指定要使用的PlatformTransactionManager的标识。这可以是bean名称或事务管理器bean的限定符值。例如,使用限定符表示法,以下Java代码

答案 5 :(得分:0)

尝试使用链接的TransactionalManager

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
public class ChainedDBConfig {

    @Bean("chainedTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("database1TransactionManager") final PlatformTransactionManager db1PlatformTransactionManager,
            @Qualifier("database2TransactionManager") final PlatformTransactionManager db2PlatformTransactionManager) {

        return new ChainedTransactionManager(db1PlatformTransactionManager, db2PlatformTransactionManager);
    }

}

并在服务类上放置以下注释:

@Transactional(transactionManager = "chainedTransactionManager")
public class AggregateMessagesJobIntegrationTest {
   ...
}

您也可以在集成测试中使用它:

@RunWith(SpringRunner.class)
@Transactional(transactionManager = "chainedRawAndAggregatedTransactionManager")
@Rollback
public class ExampleIntegrationTest extends AbstractIntegrationTest {
    ....
}

,它将对两个数据库事务管理器进行回滚。

答案 6 :(得分:0)

我必须在一个项目中使用JPA和Reactive Mongo。最后起作用的是:

  • 创建一个@Configuraition类以显式创建一个JPA事务管理器,例如here
    private Environment env;
        @Bean
        @Primary
        public LocalContainerEntityManagerFactoryBean dbEntityManager() {
            LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
            em.setDataSource(dbDatasource());
            em.setPackagesToScan(new String[]{"projectone.mysql"});
            em.setPersistenceUnitName("dbEntityManager");
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            em.setJpaVendorAdapter(vendorAdapter);

            HashMap<String, Object> properties = new HashMap<>();

            properties.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
            properties.put("hibernate.show-sql",env.getProperty("jdbc.show-sql"));


            em.setJpaPropertyMap(properties);
            return em;
        }
        @Primary
        @Bean
        public DataSource dbDatasource() {
            DriverManagerDataSource dataSource
                    = new DriverManagerDataSource();
            dataSource.setDriverClassName(
                    env.getProperty("spring.datasource.driverClassName"));
            dataSource.setUrl(env.getProperty("spring.datasource.url"));
            dataSource.setUsername(env.getProperty("spring.datasource.username"));
            dataSource.setPassword(env.getProperty("spring.datasource.password"));
            return dataSource;
        }
        @Primary
        @Bean
        public PlatformTransactionManager jpaTransactionManager() {
            JpaTransactionManager transactionManager
                    = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(
                    dbEntityManager().getObject());
            return transactionManager;
        }

}

请注意,bean名称jpaTransactionManager是JPA @Transactional中使用的txManager名称。

  • 创建MongoConfiguration以显式创建Mongo事务管理器(需要定义很多bean)
  • @Transactional中,用名字叫他们。默认的transactionManger将不起作用。您必须像jpaTransactionManagerreactiveMongoTransactionManger这样区分。
@Transactional(value="jpaTransactionManager")
public void xxx() {
    ...
}

请注意,JPA事务方法不能将Reactor类型作为返回值(Mono / Flux)。 Spring会强制返回Mono / Flux的方法使用ReactiveTransactionManager,这会引起混乱。