【问题标题】:Calling @Transactional method from non-transactional method in Spring 4.3 [duplicate]在Spring 4.3中从非事务方法调用@Transactional方法[重复]
【发布时间】:2019-07-01 04:42:18
【问题描述】:

我有以下代码:

@Service
public class ItemService {
    ...

    public void addItems(@Nonnull DocumentDTO dto) throws Exception {
        // some code that takes some time to process
        ...

        addItems(dto.getDocId(), items);
    }

    @Transactional
    public void addItems(long docId, @Nonnull List<Item> items) {
        itemDao.addItems(docId, items);
    }
}

第一个方法不是@Transactional,它用@Transactional 调用第二个方法。 SonarLint 工具指出“方法不应调用具有不兼容的“@Transactional”值的同类方法”(https://rules.sonarsource.com/java/RSPEC-2229)

但是这段代码在 Spring 4.3.20 中可以正常工作。此规则是否适用于 Spring 4.3.20?

附:有趣的是,如果我将第二种方法设为包私有,SonarLint 警告就会消失……为什么?

【问题讨论】:

  • 由于 springs 基于代理的 AOP 实现(反过来由 @Transactional 注释使用),只有在从类外部(通过代理)调用该方法时,事务才会处于活动状态。内部方法调用不会在事务中运行。
  • 要回答“为什么有效”的问题,您需要显示itemDao.addItems 代码。
  • 当你说它工作时,你看到的是成功写入数据。发生故障时回滚是行不通的。它实际上是在使用 auto_commit 进行数据库写入。

标签: java spring sonarqube aop sonarlint


【解决方案1】:

但是这段代码在 Spring 4.3.20 中可以正常工作。这个规则是真的吗 春季 4.3.20?

是的。 SonarLint 是正确的。自调用无法使@Transactional生效。它甚至在 Spring 5 中也没有改变。这就是 Spring AOP 的工作方式(参考docs)。您的代码很可能有效,因为您在 itemDao 内启动了另一个事务(可能您在 ItemDao#addItems() 上标记了另一个 @Transactional)。

如果我将第二种方法设为包私有,SonarLint 警告 消失了……为什么?

不知道为什么。也许这是一个错误。正如rule 中提到的,当在私有方法中标记@Transactional 时应该给你警告。

【讨论】:

  • 很抱歉挖掘了这个问题,但我不明白为什么这是“阻止程序”严重性的问题?在我看来,它应该警告说,如果您希望 @Transactional 在您调用第二种方法时起作用,那您就错了。但是它声明它“将导致运行时异常,因为 Spring 只“看到”调用者并且没有为正确调用被调用者做出任何规定”。这是完全不正确的。至少在这种情况下我从未遇到过任何运行时异常。您只需使用在第一种方法中创建的事务(如果有的话)。你能详细说明一下吗?
【解决方案2】:

当不需要事务时,它可能会正常工作。 @Transactional 仅适用于在 spring 创建的代理上调用的方法。这意味着,当您创建 @Service 或其他 bean 时,从外部调用的方法将是事务性的。如果从 bean 内部调用,什么都不会发生,因为它不通过代理对象。

更多详情请参考this question。

【讨论】:

    猜你喜欢
    • 2023-03-20
    • 2015-09-01
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-03
    • 2021-02-28
    • 2020-04-27
    相关资源
    最近更新 更多