首页 文章

Spring @Transactional Annotation:自我调用

提问于
浏览
5

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

我不明白为什么人们说自我调用打破了交易?只要调用方法是事务性的,不应该按预期工作吗?这里有什么我想念的吗?

2 回答

  • 0

    我不明白为什么人们说自我调用打破了交易?

    我从未听说过自我调用打破了交易 . 我所知道的是,自我调用不会启动新事务,您已经提到了原因 .

    Snippet from Spring's Transaction Management Specification

    注意在代理模式(默认设置)下,只拦截通过代理进入的外部方法调用 . 这意味着实际上,自调用目标对象中的一个方法调用目标对象的另一个方法,即使被调用的方法用@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);
    }
    

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

  • 9

    如果你可以saveAB和saveB抛出异常,你的事务就会回滚 .

    如果saveAB未使用@Transactional注释,则Seld调用将破坏跨国行为 .

    所以你没有错过你的例子中的任何内容 .

相关问题