Grails 如何处理GORM异常
我试图为Hibernate抛出的乐观锁类型异常实现异常处理,但遇到了一个奇怪的问题。似乎我无法捕捉任何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
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
对事务性服务没有影响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")
}