如何使用JPA和Hibernate修复StaleObjectStateException

时间:2014-08-27 15:21:27

标签: hibernate grails gorm staleobjectstate

控制器逻辑:

def updateObject() {

    Object o = Object.get(params.id as Long)

    o.otherObjects.clear()

    objectDataService.saveObject(o.id)

    OtherObject newObject = new OtherObject;

    o.addToOtherObjects(newObject)

    objectDataService.saveObject(o.id)

}

ServiceLogic

def saveObject(long profileId) {
    o.save(flush:true)
}

会发生什么

在90%的情况下,这将起作用。

问题

ERROR errors.GrailsExceptionResolver  - StaleObjectStateException occurred when processing request: [GET] /controller/updateObject - parameters:
stuff[]: data
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.path.Object#1]. 
Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.path.Object#1]

我已阅读相关问题并找到您在上面看到的merge电话。它解决了大约50%的案例,但并非全部。

3 个答案:

答案 0 :(得分:7)

StaleObjectStateException:

  

已经注释掉了这个例外。   如果在刷新(显式或隐式)期间会话中存在无效的版本控制域对象,则版本号会受到影响,但不会持久保存到数据库。然后,当它再次变为有效并保存和刷新时,hibernate认为它是陈旧的,因为版本号与数据库中的版本不匹配,它会抛出一个   StaleObjectStateException。

这可以解决。

  
      
  1. 您必须在执行更新之前找出版本值,如果它是1,那么您必须使用程序进行更新。在特定的更新操作。
  2.   
  3. 使用@version注释。
  4.   

关于@version:

  

通过@Version注释提供乐观锁定的版本号机制。   示例:@Version注释

@Entity
public class Flight implements Serializable {
...
    @Version
    @Column(name="OPTLOCK")
    public Integer getVersion() { ... }
} 

这里,version属性被映射到OPTLOCK列,实体管理器使用它来检测冲突的更新,并防止丢失将被last-commit-wins策略@version <覆盖的更新。 / p>

有关Grails的更多详细信息,请参阅下面的链接,它有Git hub代码 test for GRAILS-8937: HibernateOptimisticLockingFailureException

答案 1 :(得分:5)

StaleObjectStateException可以在任何其他项目中自然发生。每次两个并发事务正在加载相同的实体版本,并且由于乐观的锁定冲突失败,每个事务都会更改该实体,最终导致最后一个执行线程失败。

在您的情况下,在JPA边界之外还有一个额外的调用,可能会导致此问题:

Object o = PObject.lock(profileId)

每个事务都是线程绑定的,它发生在Session内部,因此两个竞争线程将为同一个实体id保留两个Object引用。乐观锁定目标在没有任何其他显式锁定机制的情况下有效工作。

如果您将修改后的实体引用发送到saveObject版本并且仍然遇到此异常,则表示您有两个竞争线程很有可能修改相同的实体。

在这种情况下,pessimistic lock会产生更好的结果,因为它涉及等待而不是optimistic fail-fast approach

答案 2 :(得分:3)

对于我们来说,一些不同的方法最终解决了定期发生的StaleObjectException:

object = object.refresh()

在检索它们之后刷新对象解决了我们的大多数StaleObjectExceptions。特别是在某些人有可能从其他地方处理同一个对象并改变其中一些成员的情况下(大多数问题都来自收集成员)。

整体项目稳定性:

wrongly linked resources

我们在特定资源文件上有404我们实际上并不需要,因此忽略它一段时间。事实证明,丢失的文件会导致会话保持打开状态 - 从而左右制作StaleObjects。

因此,作为对任何面临比通常更多的人的暗示(某些StaleObjects可能总是出现 - 请参见上面的答案)StaleObjectExceptions:确保所有资源正确链接您的开发者工具(Chrome F12)不会报告任何丢失的文件。