java - 彼此有 2 个本地事务(在不同的数据源上)

标签 java spring spring-transactions

我遇到交易问题。我有一种方法,需要从一个数据源读取数据,将其写入另一个数据源,然后提交到已读取数据的第一个数据源。 (第一个数据源中的数据位于队列中,我需要提交以将它们从队列中删除)。

如果我们有全局 JTA 事务,我就不会担心这个问题,但我们没有。由于架构原因,我们只能使用本地事务。 (我不是建筑师)

这是我所做的(简化):

@Transactional(value="tx1", propagation=REQUIRES_NEW)
public void copy() {
  try {
    Data data = read();
    service.write(data);
  } catch (Exception x) {...}
}

服务.java:

@Transactional(value="tx2", propagation=REQUIRES_NEW)
public void write(Data data) {
  ...
}

我知道当队列上的提交失败时我遇到了问题,因为我已经写入了数据。但这不是问题。这不是这个问题的一部分。

问题是,我收到以下错误:

2014.08.21 12:29:54 INFO : 21.08.2014 12:29:54 org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! JpaTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single JpaTransactionManager for all transactions on a single DataSource, no matter whether JPA or JDBC access.
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:311)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
    at sun.reflect.GeneratedMethodAccessor50.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
    at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:58)
    at org.springframework.osgi.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:62)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionIntercept [StdOut]
2014.08.21 12:29:54 INFO : or.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:56)
    at org.springframework.osgi.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:39)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.osgi.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy797.getTransaction(Unknown Source)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
    at org.springframewo [StdOut]
2014.08.21 12:29:54 INFO : rk.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at com.sun.proxy.$Proxy655.write(Unknown Source)

我是不是做了不该做的事?有人对我应该采取哪些不同的做法有好的建议吗?

最佳答案

这只是线索(未经测试),但太长,不适合评论。

您应该首先确保错误确实是由 2 个 @Transactional 注解方法的级联引起的,方法是首先使它们独立(请参阅我上面的评论)。对于帖子的以下内容,我认为这是真的。

您可以尝试使用显式编程事务管理,希望您对 Spring 的要求越少,副作用就越少。

// Beans to be injected
PlatformTransactionManager tx1;
PlatformTransactionManager tx2;
TransactionDefinition td1 = new ;
TransactionDefinition td2;

SessionFactory sf1;
SessionFactory sf2;

// method using explicit transactions
public void copy(Serializable id) throws Exception {
    TransactionStatus status1 = tx1.getTransaction(td1);
    try {
        Session session1 = sf1.getCurrentSession();
        Object data = session1.get("Entity", id);
        TransactionStatus status2 = tx2.getTransaction(td1);
        try {
            Session session2 = sf2.getCurrentSession();
            session2.saveOrUpdate(data);
        }
        catch (Exception e2) {
            tx2.rollback(status2);
            throw e2;
        }
        tx2.commit(status2);
    }
    catch (Exception e1) {
        tx1.rollback(status1);
        throw e1;
    }
    tx1.commit(status1);
}

但是因为 HibernateTransactionManager javadoc 中的这句话:JTA(通常通过 JtaTransactionManager)对于访问同一事务中的多个事务资源是必要的。在这种情况下,Hibernate 使用的 DataSource 需要启用 JTA(请参阅容器设置),我不确定它是否可以在 JTA 之外工作。

另一个解决方案:根据那 2 个帖子 Distributed transactions in Spring, with and without XAImplementing Spring ChainedTransactionManager according to the “best efforts 1PC” pattern ,您还可以使用 spring-data-common 中的 ChainedTransactionManager

摘自第一篇文章:

ChainedTransactionManager 的配置

<bean id="transactionManager" class="com.springsource.open.db.ChainedTransactionManager">
  <property name="transactionManagers">
    <list>
      <bean
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
      </bean>
      <bean
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="otherDataSource" />
      </bean>
    </list>
  </property>
</bean>

...请记住,资源的顺序很重要。它们是嵌套的,提交或回滚的发生顺序与它们登记的顺序(即配置中的顺序)相反

但我仍然不确定它是否可以在 JTA 之外工作......

如果这些线索都没有成功,您将不得不再次询问您的系统架构师是否不能选择 JTA。

关于java - 彼此有 2 个本地事务(在不同的数据源上),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25424420/

相关文章:

java - 与交易模板集成测试手动交易

java - 为什么变量 x 不采用我给出的值,并且当传递给其他类时变得与变量 in 相等?

java - hibernate 生成查询,无需所有外连接获取

java - 属性 : system vs. 部署描述符与属性文件的优先级

java - 为什么 OutputStream.write() 关闭套接字连接?

java - Spring JSON反序列化字符限制

java - Spring 对异步事务方法的捕获错误进行操作

java - HQL 中的 Left Join - Hibernate 查询

java - 自定义过滤器突然破坏@WebMvcTest

java - Hibernate 事务管理器 - Java 配置