录制最后以乐观锁定失败登录grails

时间:2013-09-17 06:38:30

标签: grails spring-security

我有这段代码记录'上次登录'一段时间 - 因为grails 1.3。现在处于grails 2.2.4并且'乐观锁定失败'令我烦恼。我认为这只会在我重新启动应用程序时发生。我想知道如何更好地解决它并避免'乐观锁定错误'。有弹簧安全和弹簧安全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}"
    }

要么避免这个问题,要么至少要抓住它会很棒。

1 个答案:

答案 0 :(得分:1)

使用lock代替findById。这样您就可以独享访问更新,并可以避免乐观的锁定问题。此外,不需要isDirty和附加检查,当您在会话中有一个断开连接的实例时(通常这是一个坏主意),但是您正在从数据库加载实例时更多。所以这应该有效:

ResPerson.withTransaction {
   ResPerson person = ResPerson.lock(event.authentication.principal.id)
   person.lastLoggedIn = new Date()
   person.save()
}