【问题标题】:Spring @Transactional Annotation : Self InvocationSpring @Transactional 注解:自我调用
【发布时间】:2014-07-18 20:41:08
【问题描述】:

我知道当从同一个类中调用事务方法时,它不会在事务中运行。 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 是事务性的,它仍然应该回滚。

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

【问题讨论】:

  • 你的外部方法有注释所以没有问题。但是,如果不注释外部方法,您将遇到问题,因为既没有事务,也没有saveA,也没有saveB。在这种情况下,自我调用是一个问题。

标签: java spring hibernate transactions self-invoking-function


【解决方案1】:

我不明白为什么人们说自我调用中断 交易?

我从未听说过自调用会中断事务。我只知道自调用不会启动新事务,您已经提到了原因。

来自 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);
}

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-18
      • 2014-12-24
      • 1970-01-01
      • 2021-02-11
      • 1970-01-01
      • 2021-12-24
      • 2018-03-28
      • 2015-05-15
      相关资源
      最近更新 更多