1

grails 1.3以降、しばらくの間、「最後にログインした」を記録するためにこのコードがありました。現在、grails 2.2.4 では、'楽観的ロックの失敗' に悩まされています。アプリケーションを再起動したときにのみ発生すると思います。「楽観的ロックエラー」を回避する方法を知りたいです。spring-security と spring-security-ui が関係しています。

class InteractiveAuthenticationSuccessEventListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
    private static final Logger LOG = Logger.getLogger('au.com.interlated.emissionscalculator.InteractiveAuthenticationSuccessEventListener')

    void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {

    ResPerson person
    try {
        ResPerson.withTransaction {
            person = ResPerson.findById(event.authentication.principal.id)
            if (!person.isDirty()) {
                if (!person.isAttached())
                    person.attach()


                person.lastLoggedIn = new Date()

                // doesn't save it is not the end of the world. Wondering if multiple requests at a time can cause this.
                try {
                    person.merge(flush: true)

次に、トランザクションと「person.merge」の両方で、考えられるすべてをキャッチします。この更新が行われなくても大きな問題ではありません。実際、フィルターが他の何かによって呼び出されたために作成された可能性があります。

ERROR emissionscalculator.InteractiveAuthenticationSuccessEventListener  
- Object of class [au.com.interlated.springSecurity.ResPerson] with identifier [3100]: optimistic locking failed; 
nested exception is org.hibernate.StaleObjectStateException: 
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [au.com.interlated.springSecurity.ResPerson#3100]

私はたくさんの例外をキャッチしようとしました:

    } catch (e) {
        LOG.error "Failed to save login record : ${e.message}"
    } catch (OptimisticLockingFailureException olfe) {
        LOG.error "Failed to save login record. Optimistic Locking Failure."
    } catch (org.hibernate.StaleObjectStateException sose) {
        LOG.error "Failed to save login record (stale object) ${sose.message}"
    }

問題を回避するか、少なくともそれをキャッチすることは素晴らしいことです。

4

1 に答える 1

1

lockの代わりに使用しfindByIdます。そうすれば、更新に排他的にアクセスでき、楽観的ロックの問題を回避できます。また、isDirty接続されたチェックは必要ありません。これらは、セッションで切断されたインスタンスがある場合 (一般的には悪い考えです)、データベースからインスタンスをロードしている場合に適しています。したがって、これは機能するはずです:

ResPerson.withTransaction {
   ResPerson person = ResPerson.lock(event.authentication.principal.id)
   person.lastLoggedIn = new Date()
   person.save()
}
于 2013-09-17T14:48:58.187 に答える