如何配置事务管理以在 Spring 中使用 2 个不同的数据库?

Posted

技术标签:

【中文标题】如何配置事务管理以在 Spring 中使用 2 个不同的数据库?【英文标题】:How to configure transaction management for working with 2 different db in Spring? 【发布时间】:2010-12-30 00:19:54 【问题描述】:

我有 2 个数据库(mysql 和 HSQLDB)。我配置了 2 个数据源和 2 个 EntityManagerFactory bean。我还可以配置 2 个对应的 JpaTransactionManager bean。

但我不知道如何指定它们中的哪一个应该用于管理具体服务类的事务。我想为此目的使用 @Transactional 注释,但实际上我只能指定一个 txManagers:

<tx:annotation-driven transaction-manager="manager"/>

摆脱这种情况的出路是什么?

【问题讨论】:

***.com/questions/1961371/… 【参考方案1】:

自从它在很久没有正确答案之后。

就 JpaTransactionManager 对多个数据库的可用性而言,Skaffman 可能是正确的。

但是有使用 2 个不同的数据库和 2 个不同的 JpaTransactionManager 的有效解决方案。

  @Bean(name = "db2TransactionManager")
  public PlatformTransactionManager transactionManager2() throws NamingException 
    JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
    return txManager;
  

  @Bean
  @Primary
  public PlatformTransactionManager transactionManager() throws Exception 
     JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
    txManager.setNestedTransactionAllowed(true);
    return txManager;
  

@Primary 应该用于指定在@Transactional 中未指定限定符名称的那些

【讨论】:

【参考方案2】:

您必须在 application-context.xml 中为此指定两个事务管理器,如下所示:

<tx:annotation-driven transaction-manager="manager1"/>
<tx:annotation-driven transaction-manager="manager2"/>

@Transactional 属性现在将使用其相关的事务管理器。

【讨论】:

这对我有用,我不必在 txManager bean 或 @Transactional 注释中指定限定符。我还能够访问两个不同的会话工厂。 是的,我也一样。我也不必使用 @Transactional 注释指定限定符。 有趣的是,如果我查看处理tx:annotation-drivenAnnotationDrivenBeanDefinitionParser,所有内容仅在每个上下文中完成一次!所以第二行完全没用。 这对我有用!可惜Spring官方文档没有提到设置多个DataSourceTransactionManager这个技巧。【参考方案3】:

javadoc for JpaTransactionManager 对此有一些建议:

这个事务管理器是 适用于使用的应用程序 单个 JPA EntityManagerFactory 用于 事务数据访问。 JTA (通常通过 JtaTransactionManager) 是必要的 用于访问多个事务 同一事务中的资源。 请注意,您需要配置您的 相应地,JPA 提供程序以 让它参加JTA 交易。

换句话说,如果您发现自己有多个实体管理器,以及相应的 tx 管理器,那么您应该考虑使用单个 JtaTransactionManager。实体管理器应该能够参与 JTA 事务,这将为您提供跨两个实体管理器的完全事务性,而不必担心您在任何时候都在哪个实体管理器中。

当然,JtaTransactionManager 确实需要完全支持 JTA 的应用服务器,而不是像 Tomcat 这样的普通 servlet 引擎。

【讨论】:

我可能有些不懂,但我认为 Spring 中使用的事务管理器是基于数据库事务管理器的,即我们应该创建与我们使用的不同数据库一样多的 tx-managers。错了吗? 没那么简单。 Spring TX 管理器只是围绕其他现有机制的包装器,例如 JTA、JPA/Hibernate 或 JDBC 事务。 JTA 不绑定到一个数据库,它是一个分布式多数据库 tx 管理器。使用 Spring 并没有真正改变底层机制的使用方式,它只是让它变得更容易。 谢谢,这听起来有点出乎我的意料,我会在 Sun 文档中查找。 如果我用 2 个 @Transactional() 来注释一个方法,比如 :@Transactional(transactionManager = "customerTransactionManager"), @Transactional(transactionManager = "orderTransactionManager") 会发生什么?我想知道如何在一种方法中处理两个事务性数据库。【参考方案4】:

声明你的 &lt;tx:annotation-driven&gt; 不带 transaction-manager 属性,像这样声明事务管理器的限定符:

<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <qualifier value="txManager1"/>
</bean>

@Transactional 中使用此限定符作为 来选择事务管理器之一:

@Transactional("txManager1")

或者,具有更多属性:

@Transactional(value = "txManager1", readOnly = true)   

【讨论】:

此解决方案有效。但是,如果您在 @Transactional 注释上确实有限定符,则必须指定一个配置了限定符元素的事务管理器。起初我以为默认事务管理器会接管,但对我来说不是这样。它抱怨我没有在我的事务管理器 bean 上配置适当的限定符。 请注意,这适用于 Spring 3 以后

以上是关于如何配置事务管理以在 Spring 中使用 2 个不同的数据库?的主要内容,如果未能解决你的问题,请参考以下文章

如何配置spring拦截器以在每个请求中调用

配置 Spring Security 以在认证后返回 JSON 响应

在内存(嵌入式)数据库中配置 SQL Server 以在 Spring 中进行测试

如何配置 Spring Boot 应用程序以在 MySQL 上使用 SSL/TLS?

启动时如何配置 Spring Boot 应用程序以在特定数据库上运行

如何检索 Vault 属性以在 application.yml 中配置 MongoDB 属性?