gpt4 book ai didi

hibernate - org.hibernate.StaleObjectStateException:保存域类时

转载 作者:行者123 更新时间:2023-12-02 15:29:51 27 4
gpt4 key购买 nike

我有以下代码

studentInstance.addToAttempts(studentQuizInstance)
studentInstance.merge()
studentInstance.save(flush:true)

并在上述代码的最后一行引发以下异常
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.easytha.Quiz#1]

我看到几个线程在讨论相同的问题,根据它们,我尝试使用 studentInstance.withTransactionstudentInstance.withTransaction,并且我还将服务的范围更改为请求,但到目前为止没有任何帮助。

这绝对是一个线程问题,因为仅当20到30个用户同时调用此代码时才会发生。

最佳答案

这里的核心问题是关系是双向的,并且双方都进行了更改和版本控制。当您调用addToAttempts时,将由attempts属性生成的hasMany集合初始化为一个新的空集合(如果为null),然后将其添加到实例中,并将该实例的Student字段设置为所属的Student,以确保内存中状态与以后从数据库中重新加载所有内容时的状态相同。但是,当您启用版本控制(乐观锁定)时,由于双方都发生了更改,因此两者都会发生版本冲突。因此,如果两个并发用户之间的集合重叠,则会出现此错误。这是真的-如果您未明确锁定或使用乐观锁定,则可能会丢失先前的更新。

但这完全是人为的。这看起来像多对多,因此您所要做的就是在联接表中添加新行,该行指向学生和尝试。 Grails通过配置Hibernate检测到更改的集合来做到这一点,但这实际上是在利用副作用。对于大型收藏来说,这也是非常昂贵的。我在上面省略了对addToAttempts的调用;如果那里已经有实例,即使您不需要它们,也将从数据库中检索每个实例。 Grails加载所有N个先前的元素(其中N可以是一个非常大的数字)并添加一个新的N + 1st,因此Hibernate可以检测到该新元素。您只需要插入一行,最终将产生大量的数据库流量。

解决方法不是分散在mergewithTransaction调用中,或分散在您在此处或其他地方找到的其他随机内容–而是删除并发访问。在这里,您很幸运,因为它完全是人造的。看到我刚才做的这个演讲,可悲的是仍然和当时的Grails一样重要-我描述了删除集合并将其替换为更明智的方法的方法:http://www.infoq.com/presentations/GORM-Performance

关于hibernate - org.hibernate.StaleObjectStateException:保存域类时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21285626/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com