【问题标题】:Spring JPA Service - Validation - Runtime ExceptionSpring JPA 服务 - 验证 - 运行时异常
【发布时间】:2018-03-10 07:25:07
【问题描述】:

我有一个 API,如下所示

@Transaction
void method (){
try{
  service1.insertOne();
  service2.insertTwo();
}
catch(Exception ex) {
// log exception
}
}

在服务类中,我正在检查某些验证并抛出异常,它是RuntimeException 的子类。当我抛出这个异常时,javax.persistence.RollbackException: Transaction marked as rollbackOnly。虽然它阻止了第一个服务中的数据不被插入,但由于第二个服务验证失败,我不太确定这是否是处理这种情况的正确方法。

如果异常不是Exception 的子类,即使对 service2 的验证失败,也会插入 service1 中的数据,但我确实看到抛出了自定义异常。所以我不确定我哪里出错了。任何帮助表示赞赏。

【问题讨论】:

    标签: spring-boot spring-data-jpa


    【解决方案1】:

    我不太确定这是否是处理这种情况的正确方法。

    是的,这种方式很好,当您将方法 void method () 标记为 Transactional 时,您指示只要有运行时异常,请回滚。当带有 @Transactional 注解的方法中的代码块在执行期间观察到运行时异常时,Spring 框架会将其作为标志('rollbackOnly')保留在 ThreadLocal 变量下。请注意,在 method() 完成后,如果发现标志 ('rollbackOnly') 为 false,spring 将提交。否则 spring 将指示事务管理器回滚所有插入。

    即使 service2 的验证失败,service1 中的数据也会被插入,但我确实看到了自定义异常被抛出。所以我不确定我哪里出错了

    如上所述。

    【讨论】:

      【解决方案2】:

      只需使用@Transactional 的noRollbackFor选项来指定哪个异常不应触发回滚: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html#noRollbackFor--

      @Transaction (noRollbackFor=YourRuntimeException.class)
      void method (){
          try{
            service1.insertOne();
            service2.insertTwo();
          }
          catch(Exception ex) {
          // log exception
          }
      }
      

      【讨论】:

        【解决方案3】:

        如果您的insertOne 和insertTwo 方法标记为@Transactional,则默认传播为Required。因此,您应该看到在一个事务中执行的所有操作。 Link to docs

        在第二种情况下,它也可以正常工作。如果你抛出自定义事务,那么 Spring 不会处理它。您可以通过提供rollbackFor 来更新该默认行为。在这种情况下,您会遇到与第一种情况几乎相同的情况。

        所以这对您来说是更多问题 - 您是否希望您的验证将交易标记为rollbackOnly,或者不。我会说是的。

        也许问题太抽象了。假设您要放置发票和头寸 - 那么我希望此交易能够回滚。但是,如果您添加组和用户...组可以去,因为问题在于用户。

        【讨论】:

          【解决方案4】:

          Spring 框架的事务基础结构代码仅在运行时、未经检查的异常情况下将事务标记为回滚;也就是说,当抛出的异常是 RuntimeException 的实例或子类时。

          https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-rolling-back

          因此,它必须保持为RuntimeException 的类型。

          可能你在service1.insertOne 和/或service2.insertTwo() 方法之上有Transactional 注释,这就是你得到javax.persistence.RollbackException: Transaction marked as rollbackOnly 的原因。

          您不需要那些额外的注释(如果它们存在的话),因为已经有一个活跃的事务。

          检查this answer。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-06-18
            • 2017-03-13
            • 1970-01-01
            • 2018-11-30
            • 1970-01-01
            • 2014-12-31
            相关资源
            最近更新 更多