32

我正在使用@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 个数据源,我该怎么办?

4

7 回答 7

37

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

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

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

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

@Transactional("txName")

或者

@Transactional(value = "txName")

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

于 2013-12-27T19:46:16.090 回答
9

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

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

@Service
@Transactional(value="myTxManager", readOnly = true)
public class MyServiceImpl implements MyService { ... }
于 2014-09-17T09:38:55.117 回答
5

来自java 文档

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

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

于 2011-11-08T17:09:52.330 回答
1

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

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

有关其用法的示例。

于 2011-12-07T07:50:21.997 回答
1

我必须在一个项目中使用 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 中使用的 txManager 名称@Transactional

  • createMongoConfiguration显式创建 Mongo 事务管理器(需要定义很多 bean)
  • @Transactional,用名字称呼他们。默认的transactionManger将不起作用。你必须区分,喜欢jpaTransactionManagerreactiveMongoTransactionManger
@Transactional(value="jpaTransactionManager")
public void xxx() {
    ...
}

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

于 2020-03-30T14:53:05.287 回答
0

Some of the other answers imply that using two transaction managers is in some way wrong; however, Spring's XML configuration allows for using multiple transaction managers as stated in the online documentation (below). Unfortunately, there does not seem to be a way to make the @EnableTransactionManagement annotation work in a similar manner. As a result, I simply use an @ImportResource annotation to load an XML file that includes the <tx:annotation-driven/> line. This allows you to get a Java configuration for most things but still make use of @Transactional with an optional Transaction Manager qualifier.

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

Most Spring applications only need a single transaction manager, but there may be situations where you want multiple independent transaction managers in a single application. The value attribute of the @Transactional annotation can be used to optionally specify the identity of the PlatformTransactionManager to be used. This can either be the bean name or the qualifier value of the transaction manager bean. For example, using the qualifier notation, the following Java code

于 2013-09-26T02:20:15.480 回答
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 {
    ....
}

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

于 2018-08-16T12:14:31.300 回答