17

我知道当从同一个类内部调用事务方法时,它不会在事务中运行。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没有。据我所知,即使saveA并且saveB不是事务性的(因为它们是从同一个对象调用的),因为saveAB是事务性的,它仍然应该回滚。

我不明白的是为什么人们说自我调用会破坏事务?只要调用方方法是事务性的,不应该一切都按预期工作吗?我在这里有什么遗漏吗?

4

2 回答 2

17

我不明白的是为什么人们说自我调用会破坏事务?

我从来没有听说过自我调用会破坏事务。我所知道的是自调用不会启动新事务,您已经提到了原因。

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

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


如果您@Transaction从 中删除注释saveAB(),您将观察到该方法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);
}

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

于 2014-05-29T13:34:13.190 回答
2

如果您调用saveABsaveB抛出一个Exception,您的事务将回滚。

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

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

于 2014-05-29T11:36:46.660 回答