【问题标题】:Spring @Transactional annotation when using try catch block使用 try catch 块时的 Spring @Transactional 注释
【发布时间】:2014-11-02 12:51:51
【问题描述】:

如果我们在带有@Transactional注解的方法中捕获到异常,如果发生异常会回滚吗?

@Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor=Throwable.class)
public void yearEndProcess() {
    try {
        // try block
    } catch (Throwable throwable) {
        // catch block
    }
}

【问题讨论】:

  • 在您的应用程序中尝试一下,我假设您了解 @Transactional 的作用。
  • @user3404577 你能告诉我们你的sn-p代码吗?
  • @user3404577 yearEndProcess 方法包含在哪里?包含yearEndProcess的类是Service、Component还是其他ad最终实现了一些接口?
  • 从控制器调用这个方法。而且我只想知道,如果我按照 ker p pag 提到的方式以编程方式回滚事务,那么该公司的更新会起作用吗?

标签: spring spring-mvc


【解决方案1】:

例如

class A{
    
    @Transactional
    public Result doStuff(){
        Result res = null;
        try {
          // do stuff 
        } catch (Exception e) {
            
        }
        return res ;
    }
}

如果doStuff 方法中出现异常,则事务不会回滚。

To rollback the exception programmatically,我们可以执行如下操作。

声明式方法

@Transactional(rollbackFor={MyException1.class, MyException2.class, ....})
public Result doStuff(){
   ...
}

程序化回滚

您需要从TransactionAspectSupport 调用它。

    public Result doStuff(){
      try {
        // business logic...
      } catch (Exception ex) {
        // trigger rollback programmatically
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }
    }

强烈建议您尽可能使用declarative approachrollbackProgrammatic rollback is available 仅在您绝对需要时才应使用。

【讨论】:

  • 我从同一对象的其他方法中调用此方法“yearendprocess”。这也使用@transactional 注释进行了注释。会这样吗?
  • @ankur-singhal,我不明白为什么我们需要@Transactional(rollbackFor={MyException1.class, MyException2.class, ....})?默认rollbackForThrowable,应该已经覆盖了吧?
  • 这并不总是正确的。如果插入或更新失败(即使被 try/catch 包围),这里仍然会发生回滚。这是因为当 Spring Boot 检测到 DB 错误时,它会将事务标记为rollBackOnly,无论是否捕获到异常
【解决方案2】:

来自 spring 参考文档

Spring 建议你只注解具体类(以及具体类的方法) 使用 @Transactional 注释,而不是注释接口。你当然可以 将 @Transactional 注释放在接口(或接口方法)上,但这有效 仅当您使用基于接口的代理时,您才会期望它。 Java 的事实 注释不是从接口继承的,这意味着如果您使用的是基于类的代理 ( proxy-target-class="true") 或基于编织的方面 (mode="aspectj"),然后 代理和编织基础设施无法识别事务设置,并且 对象不会被包装在事务代理中,这绝对是坏事。

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

然后使用@Transaction 默认行为是任何 RuntimeException 触发回滚,而任何已检查的异常都不会。然后你的事务回滚所有 RuntimeException 和选中的 Exception Throwable

【讨论】:

    【解决方案3】:

    你会想阅读this

    集成事务管理。您可以通过 @Transactional 注释或通过在 XML 配置文件中显式配置事务 AOP 建议,使用声明性、面向方面编程 (AOP) 样式的方法拦截器来包装您的 ORM 代码。在这两种情况下,都会为您处理事务语义和异常处理(回滚等)。如下所述,在资源和事务管理中,您还可以交换各种事务管理器,而不会影响您的 ORM 相关代码。例如,您可以在本地事务和 JTA 之间进行交换,在这两种情况下都可以使用相同的完整服务(例如声明性事务)。此外,与 JDBC 相关的代码可以在事务上与您用于执行 ORM 的代码完全集成。这对于不适合 ORM 的数据访问非常有用,例如批处理和 BLOB 流式处理,它们仍然需要与 ORM 操作共享公共事务。

    【讨论】:

      【解决方案4】:

      您已经在 @Transactional 注释中提到了属性:rollbackFor=Throwable.class。

      所以,对于任何类型的异常事务都会被回滚。

      【讨论】:

      • RuntimeException
      【解决方案5】:

      只有当你的方法抛出运行时异常并被注释为@Transactional时,事务才会回滚

      【讨论】:

        猜你喜欢
        • 2019-07-01
        • 2011-07-19
        • 2010-12-15
        • 2011-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-04
        相关资源
        最近更新 更多