Spring @Transactional方法-参与事务

5

在一个dao中,我有2个@Transactional方法。

如果我没有提供任何显式属性,

那么如果我在另一个方法的主体中运行一个方法,会发生什么?

两个方法将在同一个事务中运行吗?

3个回答

12

Spring AOP中的代理

在使用Transactional时,你正在处理类的代理对象,因此在这种情况下:

@Transactional
public void doSomeThing(){ // calling this method targets a proxy

    doSomeThingElse(); // this method targets the actual class, not the PROXY,
                       // so the transactional annotation has no effect
}

@Transactional
public void doSomeThingElse(){
}

你正在从外部调用代理,但第二个方法调用是从代理对象内部发起的,因此没有事务支持。 所以无论第二个方法中的@Transactional注释的值如何,它们自然而然地在同一个事务中运行。

因此,如果您需要分开的事务,则必须进行调用。

yourservice.doSomething();
yourservice.doSomethingElse();

来自外部。

整个场景在Spring AOP > Understanding AOP proxies章节中有很好的解释,包括这个“解决方案”:

从内部访问当前AOP代理对象

public class SimplePojo implements Pojo {

   public void foo() {
      // this works, but... gah!
      ((Pojo) AopContext.currentProxy()).bar();
   }

   public void bar() {
      // some logic...
   }
}

5
propagation 属性的默认值为 REQUIRED,意味着:支持当前事务,如果不存在则创建一个新的事务。
因此,是的 - 两种方法都将在同一个事务中运行。
但是有一个重要的建议:不要使您的 DAO 具有事务性。服务应该是具有事务性的,而不是 DAO。

在我的情况下,DAO和Service是同一件事。我只需要一个运行2个DAO方法的方法。因此,我认为我的解决方案更简单,而不是创建一个单独的Service类。如果您有反对意见,请告诉我为什么我的方法更差。我不认为仅为1个方法创建一个新类有任何意义。将所有对DAO的调用都包装到服务层中,然后呢?双重编码? - EugeneP
2
@EugeneP:将事物包装在服务中的原因是随着应用程序的增长,您将能够使用具有明确定义职责的分层架构来适应复杂性。现在看起来您的DAO已经变得比它们应该的更加复杂了。 - Nathan Hughes

4

Spring文档

注:在代理模式下(默认情况下),只有通过代理进行的外部方法调用才会被拦截。这意味着,自我调用实际上是目标对象中调用另一个方法的方法,即使调用的方法标有@Transactional,在运行时也不会导致实际事务。


好的,我看到大部分人都不知道,可以看看其他回复。那如果我明确使用传播方式为“Required”或类似的方式呢?会有帮助吗? - EugeneP
这个外部调用的事情会阻止吗?它必须有所帮助! - EugeneP
@EugeneP,只有外部方法调用被拦截,无论@Transactional的传播属性如何。但是您可以尝试使用aspectj weaving并完全控制事务过程。 PS:我没有尝试过这个(aspecj weaving transaction),所以无法提供帮助。 - Yuri.Bulkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接