我有这段代码记录'上次登录'一段时间 - 因为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}"
}
要么避免这个问题,要么至少要抓住它会很棒。
答案 0 :(得分:1)
使用lock
代替findById
。这样您就可以独享访问更新,并可以避免乐观的锁定问题。此外,不需要isDirty
和附加检查,当您在会话中有一个断开连接的实例时(通常这是一个坏主意),但是您正在从数据库加载实例时更多。所以这应该有效:
ResPerson.withTransaction {
ResPerson person = ResPerson.lock(event.authentication.principal.id)
person.lastLoggedIn = new Date()
person.save()
}