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 回答