问题 JPA多个交易经理


我有一个applicationContext.xml文件,它有一个在Spring中间件自定义应用程序中配置的两个org.springframework.orm.jpa.JpaTransactionManager(每个都有自己的持久性单元,不同的数据库)。

我想使用基于注释的事务(@Transactional),不要乱用TransactionStatus提交,保存和回滚。

一位同事提到,当有多个事务管理器时,即使正确配置了上下文文件(引用转到正确的持久性单元),也会出现这种情况。 有谁见过问题?


在您的配置中,您是否有两个事务管理器? 你有txManager1和txManager2吗?

这就是我对JPA的看法,两个不同的Spring bean是事务管理器。


5347
2017-09-16 18:56


起源



答案:


我想你有两个选择

如果您的用例从不需要在同一事务中对两个数据库进行更新,那么您可以使用两个JpaTransactionManagers,但我不确定您是否能够使用@Transactional方法?在这种情况下,您需要回退使用简单的旧机制 TransactionProxyFactoryBean来 定义事务边界,例如:

<bean id="firstRealService" class="com.acme.FirstServiceImpl"/>
<bean id="firstService"  
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="firstJpaTm"/>
    <property name="target" ref="firstRealService"/>
    <property name="transactionAttributes">
        <props>
           <prop key="insert*">PROPAGATION_REQUIRED</prop>
           <prop key="update*">PROPAGATION_REQUIRED</prop>
           <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
        </props>
    </property>
</bean>
<!-- similar for your second service -->

如果您需要跨两个数据库的事务,则需要使用JTA事务管理器。该 API 状态:

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

这意味着您将需要提供JTA事务管理器。在我们的应用程序中,我们使用类似于以下的配置:

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

<bean id="txManager" 
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManagerName" value="appserver/jndi/path" />
</bean>

如果要在appserver中部署,那么spring JtaTransactionManager需要查找appserver提供的真正符合XA的JTA事务管理器。但是,您也可以使用独立的JTA事务管理器(但我还没有尝试过)

至于配置Jpa持久性提供程序,我不是那么熟悉。您使用的JPA持久性提供程序是什么?

上面的代码基于我们的方法,我们使用本机Hibernate而不是Hibernate的JPA实现。在这种情况下,我们能够摆脱两个HibernateTransactionManager bean,并简单地确保两个SessionFactories都注入了相同的JTA TM,然后使用tx:annotation-driven元素。

希望这可以帮助


9
2017-09-16 23:56



你可以用多个数据库提供jtaTransaction的示例代码或POC吗? - dhroove
使用Atomikos示例在Tomcat中Spring JTA多个资源事务 - anasanjaria


答案:


我想你有两个选择

如果您的用例从不需要在同一事务中对两个数据库进行更新,那么您可以使用两个JpaTransactionManagers,但我不确定您是否能够使用@Transactional方法?在这种情况下,您需要回退使用简单的旧机制 TransactionProxyFactoryBean来 定义事务边界,例如:

<bean id="firstRealService" class="com.acme.FirstServiceImpl"/>
<bean id="firstService"  
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="firstJpaTm"/>
    <property name="target" ref="firstRealService"/>
    <property name="transactionAttributes">
        <props>
           <prop key="insert*">PROPAGATION_REQUIRED</prop>
           <prop key="update*">PROPAGATION_REQUIRED</prop>
           <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
        </props>
    </property>
</bean>
<!-- similar for your second service -->

如果您需要跨两个数据库的事务,则需要使用JTA事务管理器。该 API 状态:

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

这意味着您将需要提供JTA事务管理器。在我们的应用程序中,我们使用类似于以下的配置:

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

<bean id="txManager" 
    class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManagerName" value="appserver/jndi/path" />
</bean>

如果要在appserver中部署,那么spring JtaTransactionManager需要查找appserver提供的真正符合XA的JTA事务管理器。但是,您也可以使用独立的JTA事务管理器(但我还没有尝试过)

至于配置Jpa持久性提供程序,我不是那么熟悉。您使用的JPA持久性提供程序是什么?

上面的代码基于我们的方法,我们使用本机Hibernate而不是Hibernate的JPA实现。在这种情况下,我们能够摆脱两个HibernateTransactionManager bean,并简单地确保两个SessionFactories都注入了相同的JTA TM,然后使用tx:annotation-driven元素。

希望这可以帮助


9
2017-09-16 23:56



你可以用多个数据库提供jtaTransaction的示例代码或POC吗? - dhroove
使用Atomikos示例在Tomcat中Spring JTA多个资源事务 - anasanjaria


您可以拥有两个Spring事务管理器的唯一情况是,您从未同时打开这两个事务。这与分布式事务本质上没有关系 - 即使您希望两个数据源具有完全独立(但可能在时间上重叠)的事务生命周期,也会应用相同的限制。

Spring内部的事务管理器都使用Spring的TransactionSynchronizationManager,它在静态ThreadLocal变量中保留了一堆关键状态,因此事务管理器可以保证遍布彼此的状态。


3
2017-11-11 13:30