如何正确锁定和重新加载实体

Eri*_*rik 6 java mysql spring hibernate java-ee

在我的Web应用程序中,我有几个可能同时访问相同数据的线程,为什么我决定使用Hibernate实现乐观(版本控制)和悲观锁定.

目前,我使用以下模式来锁定实体并对其执行写操作(使用Springs事务管理器和事务划分与@Transactional):

@Transactional
public void doSomething(entity) {
    session.lock(entity, LockMode.UPGRADE);
    session.refresh(entity);

    // I change the entity itself as well as entites in a relationship.
    entity.setBar(...);
    for(Child childEntity : entity.getChildren()) {
        childEntity.setFoo(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,有时我会StaleObjectException在@Transactional正在刷新时告诉我,ChildEntity已同时修改并且现在版本错误.

我想我没有正确刷新entity它的孩子所以我正在使用陈旧的数据.有人可以指出如何实现这一目标吗?我的一些想法包括清除持久性上下文(会话)或session.lock(entity, LockMode.READ)再次调用,但我不确定这里的正确性.

谢谢你的帮助!

Sta*_*tas 0

为什么要让“LockMode.UPGRADE”和乐观锁同时存在?看起来像是有争议的事情。

Hibernate从不锁定内存中的对象,并且始终使用数据库的锁定机制。另外,“如果数据库不支持所请求的锁定模式,Hibernate 将使用适当的替代模式而不是抛出异常。这确保了应用程序的可移植性。”。这意味着,如果您的数据库不支持 SELECT ... FOR UPDATE,您很可能会遇到这些异常。

另一个可能的原因是您没有为子项使用“org.hibernate.annotations.CascadeType.LOCK”。