@Transactional方法调用没有@Transactional注释的另一个方法?


88

我在Service类中看到了一个被标记为的方法@Transactional,但是它也在同一类中调用了其他没有被标记为的方法@Transactional

这是否意味着对单独方法的调用导致应用程序打开与DB的单独连接或暂停父事务等?

没有任何注释的方法的默认行为是什么,而另一个带有@Transactional注释的方法调用该方法的默认行为是什么?

Answers:


116

当您调用没有@Transactional事务块的方法时,父事务将继续使用新方法。它将使用与父方法(with @Transactional)相同的连接,以及在调用的方法中引起的任何异常(不使用该异常@Transactional将导致事务按照事务定义中的配置回滚。

如果@Transactional从具有@Transactional相同实例的方法中调用带有注释的方法,则被调用方法的事务行为将不会对事务产生任何影响。但是,如果从具有事务定义的另一个方法中调用具有事务定义的方法,并且它们处于不同的实例中,则被调用方法中的代码将遵循被调用方法中给出的事务定义。

你可以发现在部分中详细声明式事务管理春季交易文件

Spring声明式事务模型使用AOP代理。因此,AOP代理负责创建交易。仅当从实例外部调用实例中具有方法的AOP代理才有效。


这是spring的默认行为吗?
goe 2011年

是。这是默认行为。
Arun P Johny

2
@Tomasz是的。但是还应该提到的是,在从另一个@Transactional方法调用的方法上更改事务传播将无效。
费尔

1
@Tomasz,那是我的意思will follow the transaction definitions given in the called method。但是,如果该调用来自同一对象实例,则该调用将不会通过负责事务维护的aop代理传播,因此不会产生任何效果。
Arun P Johny

5
@Filip,那不是完全正确的,如果您@Transactional从不同的对象/实例调用具有定义的方法,那么即使调用方法具有不同的@Transactional属性,被调用的方法也将遵循其自己的事务定义。
Arun P Johny

23
  • 这是否意味着对单独方法的调用导致应用程序打开与DB的单独连接或暂停父事务等?

那取决于传播水平。这是所有可能的液位

例如,如果传播级别为NESTED,则当前事务将“挂起”,并且将创建新的事务(注意:嵌套事务的实际创建仅对特定的事务管理器有效

  • 没有其他注释的方法的默认行为是什么,该方法被另一个带有@Transactional注释的方法调用?

默认传播级别(您称为“行为”)是必需的。如果调用的“内部”方法具有@Transactional注释(或通过XML声明式处理),则该方法将在同一事务内执行,例如,创建“没有新内容”。


没有注释的NOT_SUPPORTED子调用呢?它是继承NOT_Supported还是因为默认值REQURED而打开了新交易?例如:f1.call(){f2()}对于f1具有注释NOT_SUPPORTED,对于f2具有非注释。
戴夫

8

@Transactional标记事务边界(开始/结束),但是事务本身绑定到线程。事务一旦启动,它就会在方法调用之间传播,直到原始方法返回并且事务提交/回滚为止。

如果调用了另一个具有@Transactional批注的方法,则传播取决于该批注的传播属性。


3个答案在某种程度上彼此冲突,不确定哪个更准确。
Eric Wang

1
@EricWang只是想分享一下我今天对这种情况进行了测试,因此Arun P Johny 的答案(带有评论)对于这种内部调用情况是最准确的。
Vinay Vissh

3

如果内部方法未使用@Transactional注释,则内部方法将影响外部方法。

如果内部方法也用@Transactional注释REQUIRES_NEW,则会发生以下情况。

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

内部方法带有注释,REQUIRES_NEW并引发RuntimeException,因此它将设置其事务回滚,但不会影响外部事务。当内部事务开始时,外部事务将暂停,然后在内部事务结束后恢复运行。它们彼此独立运行,因此外部事务可以成功提交。


1
为了向初学者澄清,我非常确定innerMethod()必须与externalMethod()位于不同的bean(也就是Spring管理的java对象)上。如果它们都在同一个bean上,我认为innerMethod实际上不会使用在其注释中声明的Transactional行为。相反,它将使用outerMethod()声明中声明的内容。这是因为Spring是如何处理AOP,它用于它的@Transactional注解(docs.spring.io/spring/docs/3.0.x/spring-framework-reference/...
johnsimer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.