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



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

@EnableTransactionManagement更灵活;它会回落到a中任何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个不同事务管理器的数据源,我应该怎么做?

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

在这个类中定义一个事务管理器:

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

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

@Transactional("txName")

@Transactional(value = "txName")

这就是您将名称限定事务管理器绑定到需要它的任何地方的方式。现在,您可以拥有任意数量的事务管理器,并在需要时使用它们。

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

@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,你应该@Configuration类中删除 @EnableTransactionManagement注释,并在@Transactional注释中指定txManager,例如

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

From java doc

对于那些希望与
建立更直接关系的@EnableTransactionManagement和要使用的事务管理器beanTransactionManagementConfigurer回调接口可能被实现-注意

实现子句和@Override注释方法:

你的@Configuration类需要实现TransactionManagementConfigurer接口-实现annotationDrivenTransactionManager,它将返回对应该使用的transactionManager的引用。

我不确定您为什么使用两个transactionmanager。您可以考虑通过AbstractRoutingDataSource对多个数据源使用相同的TransactionManager。请参阅

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

为示例,说明其用法。

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

  • 创建一个@Configuraition类来显式创建JPA事务管理器,如下所示:
    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名称。

  • create MongoConfiguration显式创建Mongo事务管理器(有很多bean要定义)
  • @Transactional中的
  • 用name调用。默认的transactionManger将不起作用。你必须区分,比如jpaTransactionManagerreactiveMongoTransactionManger
@Transactional(value="jpaTransactionManager")
public void xxx() {
    ...
}

注意JPA事务方法不能将反应器类型作为返回值(Mono/Flux)。Spring会强制返回Mono/Flux的方法使用ReactiveTransactionManager,这会造成混乱。

其他一些答案暗示使用两个事务管理器在某种程度上是错误的;但是,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代码

尝试使用chained 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 {
    ....
}

,它将为两个DB事务管理器执行回滚。

相关内容

  • 没有找到相关文章

最新更新