首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >锁()方法中的Grails StaleObjectStateException

锁()方法中的Grails StaleObjectStateException
EN

Stack Overflow用户
提问于 2014-08-14 06:52:42
回答 1查看 868关注 0票数 5

当我试图在事务性服务(grails2.3.8)中锁定域对象时,我正在接收一个StaleObjectStateException:

代码语言:javascript
复制
@Transactional
class AnalyticsService {
    boolean newStreamView(Long streamId) {

    Stream stream = Stream.lock(streamId) // The exception is launched here

当然,只有在多个并发调用该服务的情况下才会发生这种情况。正如我所看到的,hibernate试图使用ID和版本参数锁定:

代码语言:javascript
复制
select id from stream where id =442 and version =305 for update

但这失败了。如果禁用域类中的乐观锁定(version: false),一切正常(hibernate只使用id锁定行)。

正如在马克·帕尔默的博客中发布的那样:

在保持乐观锁定的同时避免StaleObjectException的唯一万无一失的方法是在事务中完成所有GORM工作,并且始终使用Domain.lock(id)加载对象。在使用动态查找器或条件时,需要指定“lock”选项,以便将结果预先锁定。

他说我们应该保持乐观。

有什么安全的方法来避免StaleObjectStateException的锁定和乐观锁定吗?

如果我禁用乐观锁定(版本: false),还会出现哪些其他问题。我很担心这一点,因为这个域类是从其他服务中更新的?

提前谢谢。

EN

回答 1

Stack Overflow用户

发布于 2018-04-03 16:26:07

我们100%地通过以下方法修正了StaleStateException/OptimisticLocking问题:

  • 我们没有明确地锁定任何东西。我们调整了代码流和对象,以便使用以下方法将锁争用的可能性降到最低
  • 从所有控制器中删除所有@Transactional注释。将修改域对象的代码从控制器移动到服务中。永远不要修改控制器中的域对象。只有委托给服务(默认情况下是事务性的)来修改域对象。在这种情况下,您可能会这样做,但是要确保100%的时间都这样做。
  • 不要禁用乐观锁定,这是有原因的。没有它,就有可能覆盖来自不同事务的更新。通常,如果您在事务处理中使用显式锁或其他干预措施来解决这个问题,那么您确实需要知道您在做什么。
  • 请记住,如果您的域对象是归属到/hasMany关系的一部分,则所有相关对象的版本号在任何更新发生时都会被弹出。因此,如果两个不同的进程正在更新对象图的不同部分,那么第一个提交将使第二个进程失效并导致这一点。看看伯特·贝克华在这里说的话是否相关:https://www.youtube.com/watch?v=-nofscHeEuU。尽管他在这里讨论的是性能,但他提出的解决方案也尽量减少了版本号更新的层叠现象。
  • 同样,您在这里似乎没有这样做,但是当我们只需要进行特定的更新时,我们会尽量减少传递潜在的脏的整个域对象。所以,与orderService.update(order)不同,当我们所做的只是设置一个状态时,我们可以说orderService.setStatus('foo',orderId),让该方法执行get和update。这缩小了StaleState发生的机会窗口,因为从提取到保存的时间很短。基本上,请确保您不会在脏域对象上停留的时间比您绝对需要的时间长。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25301785

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档