如何使用JPA和Hibernate修复StaleObjectStateException

Seb*_*ger 11 grails hibernate grails-orm 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)

}
Run Code Online (Sandbox Code Playgroud)

ServiceLogic

def saveObject(long profileId) {
    o.save(flush:true)
}
Run Code Online (Sandbox Code Playgroud)

怎么了

在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]
Run Code Online (Sandbox Code Playgroud)

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

Rud*_*dra 9

StaleObjectStateException:

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

这可以解决.

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

关于@version:

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

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

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

有关Grails的更多详细信息,请参阅下面的链接,它有Git中心代码.
测试GRAILS-8937:HibernateOptimisticLockingFailureException


Vla*_*cea 6

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

在您的情况下,在JPA范围之外还有一个额外的电话,可能会解决此问题:

Object o = PObject.lock(profileId)
Run Code Online (Sandbox Code Playgroud)

每个事务都是线程绑定的,并且发生在会话内,因此两个竞争线程将为相同的实体ID保留两个对象引用。乐观锁定目标无需任何其他明确的锁定机制即可有效地工作。

如果将修改后的实体引用发送给该saveObject版本,并且仍然出现此异常,则意味着两个竞争线程修改同一实体的可能性很高。

在这种情况下,悲观锁将产生更好的结果,因为它涉及等待而不是乐观的快速失败方法


Seb*_*ger 4

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

object = object.refresh()
Run Code Online (Sandbox Code Playgroud)

检索对象后刷新它们解决了大部分 StaleObjectExceptions。特别是在有人可能从其他地方处理同一个对象并更改其某些成员的情况下(大多数问题都与集合成员有关)。

项目整体稳定性:

wrongly linked resources
Run Code Online (Sandbox Code Playgroud)

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

因此,作为对任何面临异常情况的人的提示(某些 StaleObjects 可能总是会发生 - 请参阅上面的答案) StaleObjectExceptions:确保所有资源都正确链接,并且您的开发人员工具(Chrome F12)不会报告任何丢失的文件。