我想实现的异常处理由Hibernate抛出乐观锁型异常,但我遇到一个奇怪的问题。 看来我无法捕捉任何异常格姆。
例如,我在我的服务的代码:
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的标准异常处理程序。 该catch块永远不会被调用,即使报道的例外是StaleObjectStateException
。
我注意到,我能赶上的异常,如果我让它传播到控制器,赶上它在那里,但似乎我不能在这诡异的服务实现的异常处理。
我在想什么?
我得到了这条底线,我张贴万一别人运行到这一点。 出现该问题的原因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
}
在这种情况下,模型是任何GORM模型类,无所谓哪一个。 尤其是如果它是类传入的对象也没关系。
使用示例:
AnotherModelClass object = AnotherModelClass.get(id)
retryUpdate(object) {
object.setField("new value")
}