【问题标题】:Why new spring transactions are created when I call a method of another service?为什么当我调用另一个服务的方法时会创建新的 Spring 事务?
【发布时间】: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 时都会创建一个新事务。但是,如果我删除标有“##”的行,则整个过程只创建一个事务,允许在发生异常时回滚。

  1. 这是预期的弹簧行为吗?
  2. 有什么方法可以让 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


【解决方案1】:

执行 Propagation.REQUIRED 以支持当前事务而不是创建新事务。删除 Transactional 注释是一种不好的做法,因为调用者需要事务行为,并且方法本身可能不安全

【讨论】:

  • 如果您的意思是在 CalledService 上指定 @Transactional(propagation = Propagation.REQUIRED),如我的问题所述,我已经尝试过了。
  • 我的意思是方法上的事务注释,而不是你帖子中的类
  • 就像他说的那样,这是默认设置。他的例子表明他已经指定了@Transational;并且它已经默认为 REQUIRED(根据文档)
  • 我们都明白 Propagation.REQUIRED 是默认的,但是他的代码不起作用,所以我提出了一个试探性的。强制 @Transational 注释将其放置在每个方法签名上而不是类声明上,就像代码片段中的看到一样,以证明行为可能发生变化。一直说 Propagation.REQUIRED 是默认设置对解决问题没有多大帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-28
  • 1970-01-01
  • 1970-01-01
  • 2012-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多