Grails:乐观锁定,StaleObjectStateException 与 Spring Security 会话中的域,更新计数器

Posted

技术标签:

【中文标题】Grails:乐观锁定,StaleObjectStateException 与 Spring Security 会话中的域,更新计数器【英文标题】:Grails: Optimistic locking, StaleObjectStateException with domain on session with Spring Security, updating counters 【发布时间】:2011-05-06 06:36:41 【问题描述】:

我有一个 Grails 应用程序,人们通过 Spring Security 登录。然后在登录期间将他们的用户域加载到会话中。

当另一个用户执行更新数据库user.save(flush:true) 中的用户对象的计数器的操作时,我收到了 StaleObjectStateException,该用户对象当前在登录用户的另一个会话中

例如我在登录用户 A 的会话中有“用户 A”对象。 然后当用户 B 登录并执行操作以更新用户 A 对象但版本不同步时。

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.example.User#2]

        at $Proxy12.merge(Unknown Source) 

我尝试过合并,但没有成功。

我正在考虑完全去掉“版本”属性,因为用户域上的更新太多了,数百个用户会登录。但我不知道这会对一致性产生什么影响随时间变化的数据。

user.save(flush:true) 换成User.executeUpdate(Update viewCount where ...) 会解决问题并带来更多缓存问题吗?

或者我可以选择在更新它们时可以忽略“版本”的特定属性。 我真的不明白这个例子发生了什么。 http://grails.1312388.n4.nabble.com/GORM-setting-access-field-td1592837.html

那我该如何解决呢?

【问题讨论】:

【参考方案1】:

已解决:会话中基本上没有用户域。只是用户 ID。因此,您可以在需要使用时加载域。

解决方案是不在会话中使用域对象。请改用 id,然后为需要用户数据的每个请求加载对象。这是 grails 的 spring 安全插件中引入的差异。欲了解更多信息,请查看此处(官方文档):

http://burtbeckwith.github.com/grails-spring-security-core/docs/manual/guide/2%20Differences%20Between%20the%20Spring%20Security%20and%20Acegi%20Plugins.html

【讨论】:

您能否举例说明如何为每个请求加载对象以避免在会话中使用域对象? 当你为第一个请求加载一个对象时,它不是在那之后的会话中吗?然后你可以丢弃/驱逐,但我不知道在那之后如何取回它。

以上是关于Grails:乐观锁定,StaleObjectStateException 与 Spring Security 会话中的域,更新计数器的主要内容,如果未能解决你的问题,请参考以下文章

Spring data - 启用乐观锁定

乐观与悲观锁定

何时明确排除乐观锁定(休眠)?

休眠乐观锁定..它是如何工作的?

在 Oracle 中实现乐观锁定

JPA 和乐观锁定模式