【发布时间】:2016-02-19 04:17:18
【问题描述】:
我有两个服务。一个从数据库加载数据,修改它们并调用另一个服务来持久化修改后的数据:
@Service
@Transactional
public class CallerService {
public void doSomething() {
List dataList = loadData();
for(data : dataList) {
data.setValue("newValue");
calledService.persistData(data);
}
}
}
@Service
@Transactional //##
public class CalledService {
public void persistData(Data data){
myDao.persistData(data);
}
}
使用这样的代码,每次调用 CalledService.persistData 时都会创建一个新事务。但是,如果我删除标有“##”的行,则整个过程只创建一个事务,允许在发生异常时回滚。
- 这是预期的弹簧行为吗?
- 有什么方法可以让 CalledService 保持事务性并避免在从 CallerService 到 CalledService 时创建新事务?
请注意,我确实尝试将传播更改为“必需”以及 CalledService 上的其他几个值。
编辑: 这是来自 persistData 的堆栈跟踪:
CalledServiceImpl.persistData(Reglement, int, Gestionnaire) line: 304
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 606
AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[]) line: 317
ReflectiveMethodInvocation.invokeJoinpoint() line: 190
ReflectiveMethodInvocation.proceed() line: 157
TransactionInterceptor$1.proceedWithInvocation() line: 99
TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class<?>, InvocationCallback) line: 281
TransactionInterceptor.invoke(MethodInvocation) line: 96
ReflectiveMethodInvocation.proceed() line: 179
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 207
$Proxy51.persistData(Data) line: not available
CallerServiceImpl.doSomething(String) line: 277
CallerServiceImpl.runBatch(String[]) line: 178
CallerServiceImpl(BatchAbstractService).doBatch(String[]) line: 29
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43
Method.invoke(Object, Object...) line: 606
AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[]) line: 317
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 201
$Proxy95.doBatch(String[]) line: not available
ClientBatch.process(String, String[]) line: 78
ClientBatch.main(String[]) line: 53
EDIT2:CallerService 和 CalledService 不在同一个项目中。如果我把它们放在同一个项目中,当过程中发生异常时,事务会适当回滚。
【问题讨论】:
-
您是否已证明您的交易代理已到位?即您的配置是否正确?如果您将断点设置为
CalledService#presistData(Data),您可以在该点引用堆栈跟踪吗?这将验证您的问题是没有设置跨国代理。然后你/我们可以通过了解这一点进行调试。 -
好的,我们可以在堆栈跟踪中看到 Transaction 的内容,所以..您确定在您期望数据已经提交之前的某个时刻离开了
@Transactional的外部范围吗?您说每次调用 CalledService 时都会创建一个新事务,这是不正确的,有一个事务并且 Caller 和 Called 都加入了该事务。因此,为什么我要在检查 DB 中提交的数据之前离开外部@Transactional边界。要进行新事务,请参阅对内部 (CalledService) 的@Transactional(propagation=Propagation.REQUIRES_NEW)的支持。 -
请看我的“EDIT2”。
-
“不在同一个项目中”是什么意思?更重要的不是它们所在的 IDE 项目(或 JAR),而是每层运行的上下文。例如 CalledService 可能是在 AS 中运行的 EJB,但 CallerService 可能在 EJB 客户端代码中,因此使用了 2 个 JVM。事务管理本身并不关心您对单独项目的逻辑表示法。
标签: java spring transactions