exception - Grails UnexpectedRollbackException发生: Not Sure Why

标签 exception grails transactions

我有以下代码:

class ServiceA {

   def save(Object object) {
      if (somethingBadComesBack) {
         throw new CustomRuntimeException(data)
      }
   }
}

class ServiceB {

   def serviceA

   def save(Object object) {
      try {
         serviceA.save(object)
         // do more stuff if good to go
      } catch(CustomRuntimeException e) {
        // populate some objects with errors based on exception
      }
   }
}

class ServiceC {

    def serviceB

    def process(Object object) {
       serviceB.save(object)
       if (object.hasErrors() {
          // do some stuff
       }else{
         // do some stuff
       }

       def info = someMethod(object)
       return info
    }
}

class SomeController {

   def serviceC

   def process() {

     def object = .....
     serviceC.save(object) // UnexpectedRollbackException is thrown here

   }
}

调用ServiceA.save()并发生异常时,ServiceC.save()尝试返回时会抛出UnexpectedRollbackException

我做了以下事情:
try {
   serviceC.process(object)
}catch(UnexpectedRollbackException e) {
   println e.getMostSpecificCause()
}

我得到:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

我不确定从哪里开始寻找解决方法。

最佳答案

您正在使用运行时异常来回滚事务,但这是作弊-它利用了副作用。运行时异常会自动回滚事务,因为您不需要捕获它们,因此假定如果引发了异常,则不会发生,默认行为是回滚。您可以将方法配置为不为特定的预期运行时异常回滚,但这很少见。被检查的异常不会回滚异常,因为在Java中必须捕获它们或在throws中声明它们,因此您必须显式地抛出它或将其隐藏。无论哪种方式,您都有机会再试一次。

正确回滚事务的正确方法是在当前setRollbackOnly()上调用TransactionStatus,但这不能在服务方法中直接访问(由于它是闭包的参数,因此在withTransaction块中)。但是很容易做到:导入org.springframework.transaction.interceptor.TransactionAspectSupport并调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。这将需要您对代码进行重新处理,因为不会捕获任何异常,因此您需要检查它是否已使用TransactionAspectSupport.currentTransactionStatus().isRollbackOnly()回滚。

我不确定这是Grails的问题还是标准行为,但是在进行调试时,使用3个不同的TransactionStatus实例进行了3次commit调用。只有第一个设置了回滚标志,但是第二个知道了第一个并且还可以。第三个被认为是新事务,并且触发了您所看到的相同异常。因此,要解决此问题,我将其添加到了第二和第三服务方法中:

def status = TransactionAspectSupport.currentTransactionStatus()
if (!status.isRollbackOnly()) status.setRollbackOnly()

链接回滚标志。那行得通,我没有得到UnexpectedRollbackException

将其与检查的异常结合起来可能会更容易。它仍然过于昂贵,因为它将不必要地填充stacktrace,但是如果您调用setRollbackOnly()并抛出一个已检查的异常,那么您将能够使用与现在相同的常规工作流程。

关于exception - Grails UnexpectedRollbackException发生: Not Sure Why,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13482103/

相关文章:

python - MySQLdb 显示警告时出现 UnicodeEncodeError

grails - tcServer JVM 崩溃 - EXCEPTION_ACCESS_VIOLATION (0xc0000005)

c# - 服务器无法恢复事务 事务

ios - 在 Swift 中使用 FMDB 回滚事务

android - 在 uncaughtException() 调用上开始 Activity

c# - 在单元测试中出现 OutOfMemoryException

java - FaceDetector 无法解析为类型

java - Grails日志配置正在劫持外部日志配置,如何阻止它?

grails - Grails 中的帮助气球

database - 由于这种模式,在同一个结构中使用事务和简单的数据库连接我该怎么办?