我遇到了交易问题。我有一个方法需要从一个数据源读取数据,将其写入另一个数据源,然后提交到已读取数据的第一个数据源。 (第一个数据源中的数据在队列中,我需要提交将它们从队列中删除)。
如果我们进行全球JTA交易,我不会担心这一点,但我们不会这样做。由于架构原因,我们只能使用本地交易。 (我不是建筑师)这是我做的(简化):
@Transactional(value="tx1", propagation=REQUIRES_NEW)
public void copy() {
try {
Data data = read();
service.write(data);
} catch (Exception x) {...}
}
Service.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)
我正在做一些不应该做的事情吗?任何人都对我应该做的不同有很好的建议吗?
答案 0 :(得分:1)
这只是线索(没有经过测试),但是太长了,不适合评论。
首先应确保错误确实是由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之外工作。
另一种解决方案:根据这两篇帖子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是否不是一个选项。