我遇到交易问题。我有一种方法,需要从一个数据源读取数据,将其写入另一个数据源,然后提交到已读取数据的第一个数据源。 (第一个数据源中的数据位于队列中,我需要提交以将它们从队列中删除)。
如果我们有全局 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 XA和 Implementing 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/