3

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");
}

このブロックを2つのスレッドでヒットすると、ブロックが爆発し、例外がGrailsの標準例外ハンドラーに伝播します。報告された例外が。であっても、catchブロックが呼び出されることはありませんStaleObjectStateException

コントローラに伝播させてそこでキャッチすれば例外をキャッチできることに気づきましたが、奇妙なサービスで例外処理を実装できないようです。

私は何が欠けていますか?

4

2 に答える 2

7

私はこれの底に到達し、他の誰かがこれに遭遇した場合に備えてそれを投稿しています。この問題は、try/catchブロックがトランザクションサービスにあったために発生しました。grailsは、save()呼び出し中に例外がスローされたと報告しましたが、実際には、トランザクションがコミットされたときに、メソッド全体の後で呼び出されました。

したがって、次のようになります。

  1. flush: trueトランザクションサービスには影響しません
  2. トランザクションサービスでGORM関連の例外をキャッチすることはできません。少なくとも、いくつかの作業が必要です。

私は最終的に自分でトランザクションを手動で管理することでこれを回避しました。

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

これが他の誰かに役立つことを願っています!

于 2012-09-17T08:18:56.367 に答える
1

私はこの問題に取り組むことに時間を費やし、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")
}
于 2014-04-17T02:59:35.297 に答える