【问题标题】:Can't solve HibernateOptimisticLockingFailureException in Grails 2.4.5无法解决 Grails 2.4.5 中的 HibernateOptimisticLockingFailureException
【发布时间】:2015-07-13 20:27:31
【问题描述】:

我已经尝试了好几个小时来弄清楚为什么我无法解决这个问题。

基本上,我有一个域类 (PrizeSchedule),它在我的应用程序中用于安排何时发放奖品。当收到请求并且是发放奖品的时间(计划时间比现在短)时,它将分配该奖品并将其标记为已处理。

这意味着,如果参赛作品之间有足够的时间间隔,则可能有 2 个或更多奖品可供赠送。当我直接使用 10 个(或更多)请求测试我的应用程序时,在这种情况下,我总是在一些请求上遇到以下问题:

optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

我尝试过使用prizeScheduleInstance.merge 和prizeScheduleInstance.lock,但弹出相同的错误。很长一段时间后,我发现 PrizeSchedule.find() 调用没有产生正确的结果。尽管之前的请求完成了以下操作,但似乎:

prizeSchedule.setProcessed(true);
prizeSchedule.setReferenceNumber(prizeSchedule.generateToken());           
prizeSchedule.save(flush:true);

下一个请求仍然能够找到处理后的 PrizeSchedule 实例,您可以在下面的日志中看到这里

请求 1:

2015-07-13 22:05:28,915 [http-bio-8080-exec-7] DEBUG PrizeService  - Session ID: 603 won prize ID: 103314

请求 2:

2015-07-13 22:05:30,136 [http-bio-8080-exec-12] DEBUG PrizeService  - Session ID: 604 won prize ID: 103314

如您所见,第二个请求仍然以某种方式找到了 PrizeSchedule 实例,即使已处理标志已被标记为 true。

我尝试了这个查询的变体来查找 PrizeSchedule 实例,它们都产生相同的问题,下面是我尝试过的问题

PrizeSchedule ps = PrizeSchedule.findByCampaignAndDateScheduledLessThanAndProcessed(campaign, new Date(), false, [cache: false])

PrizeSchedule ps = ps = PrizeSchedule.find("FROM PrizeSchedule ps WHERE ps.campaign = :campaign AND ps.processed = :processed AND ps.dateScheduled < :now ORDER BY ps.dateScheduled ASC",
        [campaign: campaign, processed: false, now: new Date()], [cache: false]
    )

如果它很重要 - 我有调用服务来处理请求的控制器,这反过来又调用其他 groovy/src 代码,这些代码通过使用 PrizeService

def prizeService = Holders.grailsApplication.mainContext.getBean 'prizeService'

这是因为在这些领域中使用了通用接口和抽象类。

希望有人能提供帮助,提前感谢您抽出宝贵时间阅读本文!

【问题讨论】:

  • 无需挖掘比您发布的更多代码,您应该非常关注的第一件事是使用Holders 进行DI。这是一个巨大的危险信号,表明您的设计存在根本缺陷。使用Holders 应该与正在创建的宇宙一样罕见。我不是在开玩笑。
  • 老实说,我这样做是出于绝望 - 我直接在 groovy/src 中使用对象,我认为这可能与那些不遵守 @Transactional 方法注释的人有关(不是完全理解 Hibernate)——同样的问题发生在不使用 Holders 并直接在 groovy/src 中进行分配的情况下。感谢您指出这一点 - 我将重新调整代码,使其恢复原状。
  • @JoshuaMoore 我已将其改回为直接从 groovy/src 块运行代码 - 相同的行为:(

标签: hibernate grails asynchronous groovy


【解决方案1】:

好的,我将其发布为我的问题的解决方案,以防万一其他人将来遇到此问题。这可能很明显,但作为 Grails 的新手,我发现这很难解决/查找相关信息。

基本上我的控制器被注释了

@Transactional(readOnly = true)

并且进行实际处理的方法带有注释

@Transactional

最后,服务本身也被注释了

@Transactional

我的假设是这些注释以某种方式混合了在 Hibernate 会话中访问和存储数据时使用的事务。从我的控制器中删除注释(并调整代码)并将我的服务作为@Transactional 组件后 - 一切都开始按预期工作。

我希望这可以帮助像我一样受苦的人!

【讨论】:

    【解决方案2】:

    我希望您明白,当您使用乐观锁定进行并发更新时,有可能会抛出 StateObjectStateException。随着模型中并发性的增加,它会变得越来越普遍。

    由于您提到这是计划作业的一部分,您可以拥有在新会话中重试奖励授予的代码,例如,安排另一个作业立即再次运行。

    【讨论】:

    • 我当然明白这一点,但是,它不是一个计划的作业(基于事件),我从数据库中获取相同对象的唯一原因是/是由于不正确/缓存的结果从 find() 返回。我已经解决了这个问题(见我的回答)。感谢您的宝贵时间
    猜你喜欢
    • 1970-01-01
    • 2016-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多