如何处理异常格姆(How to handle GORM exceptions)

2019-07-31 15:46发布

我想实现的异常处理由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

我注意到,我赶上的异常,如果我让它传播到控制器,赶上它在那里,但似乎我不能在这诡异的服务实现的异常处理。

我在想什么?

Answer 1:

我得到了这条底线,我张贴万一别人运行到这一点。 出现该问题的原因try / catch块是在一个事务性的服务。 虽然Grails的报道说,在异常被抛出save()调用,在现实中,它被称为整个方法之后 ,事务提交时。

如此看来,:

  1. flush: true对交易服务没有影响
  2. 这是不可能赶上交易服务格姆相关的异常,至少在没有一些工作

我终于解决此工作由手工管理自己的事务,即

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

我希望这是利用别人!



Answer 2:

我花了一些时间在这个问题上的工作,并写了一个更完整的解决方案来处理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")
}


文章来源: How to handle GORM exceptions