Grails 如何处理GORM异常

Grails 如何处理GORM异常,grails,exception-handling,gorm,Grails,Exception Handling,Gorm,我试图为Hibernate抛出的乐观锁类型异常实现异常处理,但遇到了一个奇怪的问题。似乎我无法捕捉任何Gorm异常 例如,我的服务中有以下代码: try { User user = User.get(1); Thread.sleep(10000); user.viewedAt(new Date()); user.save(flush:true); } catch (OptimisticLockingException ex) { log.error("Optimistic l

我试图为Hibernate抛出的乐观锁类型异常实现异常处理,但遇到了一个奇怪的问题。似乎我无法捕捉任何Gorm异常

例如,我的服务中有以下代码:

try {
  User user = User.get(1);
  Thread.sleep(10000);
  user.viewedAt(new Date());
  user.save(flush:true);
} catch (OptimisticLockingException ex) {
  log.error("Optimistic lock exception");
} catch (StaleObjectStateException ex) {
  log.error("Optimistic lock exception");
}
当我用两个线程点击这个块时,它爆炸了,异常传播到Grails的标准异常处理程序。即使报告的异常是
StaleObjectStateException
,也不会调用catch块

我注意到,如果我让异常传播到控制器并在那里捕获它,我就可以捕获异常,但似乎我无法在服务中实现异常处理,这很奇怪


我遗漏了什么?

我已经找到了问题的症结所在,我正在发布它,以防其他人遇到这个问题。出现此问题是因为try/catch块位于事务性服务中。尽管grails报告异常是在
save()
调用期间引发的,但实际上,在提交事务时,它是在整个方法之后调用的

看来:

  • flush:true
    对事务性服务没有影响
  • 在事务性服务中捕获与GORM相关的异常是不可能的,至少在没有一些工作的情况下是不可能的
  • 我最终通过自己手动管理事务来解决这个问题

    try {
      User.withNewTransaction {
        User user = User.get(id); // Must reload object
        .. // do stuff
        user.save(flush:true)
      }
    } catch (OptimisticLockingException ex) {
      ...
    }
    

    我希望这对其他人有用

    我花了一些时间研究这个问题,并编写了一个更完整的解决方案来处理Grails中乐观锁定异常的情况

    首先,尽管堆栈跟踪中报告的异常是StaleObjectStateException,但引发的实际异常是HibernateOptimisticLockingFailureException(而不是“OptimisticLockingException”)。其次,如果您想将其推广到处理修改域对象的任意闭包,则需要重新抛出闭包中抛出的异常

    以下静态函数将获取一个对象和一个在该对象上运行的闭包,保存它,如果失败,请重试,直到成功:

    public static retryUpdate(Object o, Closure c) throws Exception {
        def retVal
        int retryCount = 0
        while (retryCount < 5) {
            try {
                Model.withTransaction { status ->
                    retVal = c(status)
                    o.save()
                }
                return retVal
            } catch (HibernateOptimisticLockingFailureException e) {
                log.warn "Stale exception caught saving " + o
                if (++retryCount >= 3) { // if retry has failed three times, pause before reloading
                    Thread.sleep(1000)
                }
                o.refresh()
            } catch (UndeclaredThrowableException e2) {
                // rethrow exceptions thrown inside transaction
                throw e2.getCause()
            }
        }
    
        return null
    }
    

    感谢您分享您的发现和解决方案。这似乎有点违反直觉,所以如果你觉得慈善,请将你的发现发布到Grails邮件列表中,这样就可以纠正这种行为,或者围绕这个问题添加更好的文档。我想知道这里是否还有其他事情。我在一个非事务方法(既不是服务类也不是标记为事务的方法)中尝试了这个解决方案,但它仍然抛出异常,然后异常会向上传播。
    AnotherModelClass object = AnotherModelClass.get(id)
    retryUpdate(object) {
        object.setField("new value")
    }