Spring @事务性注释:自我调用



我知道当从同一个类内部调用事务方法时,它不会在事务中运行。Spring为事务性方法创建代理,并将它们包装在try-catch块中,并在发生异常时回滚。考虑以下场景:

@Transactional
public void saveAB(A a, B b)
{
    saveA(a);
    saveB(b);
}
@Transactional
public void saveA(A a)
{
    dao.saveA(a);
}
@Transactional
public void saveB(B b)
{
    dao.saveB(b);
}

假设从另一个对象调用saveAB,并且saveB发生异常,因此saveA成功完成而saveB未完成。据我所知,即使saveAsaveB不是事务性的(因为它们是从同一个对象调用的),由于saveAB是事务性的,它仍然应该回滚。

我不明白的是为什么人们说自调用破坏事务?只要调用方方法是事务性的,难道不应该一切都像预期的那样工作吗?我还遗漏了什么吗?

我不明白的是为什么人们说自我调用中断事务?

我从未听说过自调用会破坏事务。我所知道的是,自调用不会启动一个新的事务,你已经提到了原因。

来自Spring事务管理规范的代码片段

注意在代理模式下(这是默认的),只有外部方法调用通过代理进入被拦截。这意味着自调用,实际上是在目标对象内调用的方法另一种方法的目标对象,不会导致实际的事务处理,即使调用的方法被标记为@ transactional .


如果您从saveAB()中删除@Transaction注释,您将观察到方法saveA()saveB()即使使用@Transactional注释也不会在事务下运行。但是,如果从类外部调用saveA()saveB(),它将按照预期在事务下运行。这就是为什么人们建议要小心自我祈祷的原因。

public void saveAB(A a, B b)
{
    saveA(a);
    saveB(b);
}
@Transactional
public void saveA(A a)
{
    dao.saveA(a);
}
@Transactional
public void saveB(B b)
{
    dao.saveB(b);
}

在我看来,自调用任何公共方法都是一个坏主意。

如果你调用saveAB并且saveB抛出一个Exception,你的事务将回滚。

自调用不会破坏事务上下文,因为默认的事务传播是REQUIRED,这意味着在新bean上调用新的@Transactional方法时重用相同的事务上下文。

但是,在同一个bean中,调用新方法不经过TransactionalInterceptor,因此重用了完全相同的事务上下文。

最新更新