Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate 删除实体时避免StaleObjectStateException_Hibernate_Transactional_Pessimistic Locking_Staleobjectstate - Fatal编程技术网

Hibernate 删除实体时避免StaleObjectStateException

Hibernate 删除实体时避免StaleObjectStateException,hibernate,transactional,pessimistic-locking,staleobjectstate,Hibernate,Transactional,Pessimistic Locking,Staleobjectstate,我有两个并发线程,它们同时进入(Spring)事务服务 使用Hibernate,服务方法加载一些实体,处理这些实体,找到一个实体并将其从数据库中删除。伪代码如下所示: @Transactional public MyEntity getAndDelete(String prop) { List<MyEntity> list = (List<MyEntity>)sessionFactory .getCurrentSession() .

我有两个并发线程,它们同时进入(Spring)事务服务

使用Hibernate,服务方法加载一些实体,处理这些实体,找到一个实体并将其从数据库中删除。伪代码如下所示:

@Transactional
public MyEntity getAndDelete(String prop) {
    List<MyEntity> list = (List<MyEntity>)sessionFactory
        .getCurrentSession()
        .createCriteria(MyEntity.class)
        .add( Restrictions.eq("prop", prop) )
        .list();

    // process the list, and find one entity
    MyEntity entity = findEntity(list);
    if (entity != null) {
        sessionFactory.getCurrentSession().delete(entity);
    }
    return entity;
}
@Transactional
public MyEntity getAndDelete(String prop) {
    List<MyEntity> list = (List<MyEntity>)sessionFactory
        .getCurrentSession()
        .createCriteria(MyEntity.class)
        .add( Restrictions.eq("prop", prop) )
        .list();

    // process the list, and find one entity
    MyEntity entity = findEntity(list);
    if (entity != null) {
        // reload the entity with "select ...for update"
        // to ensure the exception is not thrown
        MyEntity locked = (MyEntity)sessionFactory
            .getCurrentSession()
            .load(MyEntity.class, entity.getId(), new LockOptions(LockMode.PESSIMISTIC_WRITE));
        if (locked != null) {
            sessionFactory.getCurrentSession().delete(locked);
        }
    }
    return entity;
}
我使用
load()
而不是
get()
,因为根据hibernate API,如果已经在会话中,get将返回实体,而load应该重新读取它

如果两个线程同时进入上面的方法,其中一个线程会阻止锁定阶段,当第一个线程关闭事务时,第二个线程被唤醒,抛出
org.hibernate.StaleObjectStateException
。为什么?


为什么锁定的加载不只是返回null?我怎样才能做到这一点呢?

我花了一些时间研究这个问题,终于明白了会发生什么

悲观写锁尝试“锁定”会话中已加载的实体,但不会从数据库中重新读取对象。调试调用时,我看到
entity==locked
返回
true
(用Java术语)。两个变量都指向同一个实例

要强制hibernate重新加载实体,必须首先将其从会话中删除

下面的代码实现了这一点:

@Transactional
public MyEntity getAndDelete(String prop) {
    List<MyEntity> list = (List<MyEntity>)sessionFactory
        .getCurrentSession()
        .createCriteria(MyEntity.class)
        .add( Restrictions.eq("prop", prop) )
        .list();

    // process the list, and find one entity
    MyEntity entity = findEntity(list);
    if (entity != null) {

        // Remove the entity from the session.
        sessionFactory.getCurrentSession().evict(entity);

        // reload the entity with "select ...for update"
        MyEntity locked = (MyEntity)sessionFactory
            .getCurrentSession()
            .get(MyEntity.class, entity.getId(), new LockOptions(LockMode.PESSIMISTIC_WRITE));
        if (locked != null) {
            sessionFactory.getCurrentSession().delete(locked);
        }
    }
    return entity;
}
@Transactional
公共MyEntity getAndDelete(字符串属性){
列表=(列表)会话工厂
.getCurrentSession()
.createCriteria(MyEntity.class)
.添加(限制条件。等式(“道具”,道具))
.list();
//处理列表,并找到一个实体
MyEntity实体=findEntity(列表);
如果(实体!=null){
//从会话中删除实体。
sessionFactory.getCurrentSession().Recit(实体);
//使用“选择…进行更新”重新加载实体
MyEntity locked=(MyEntity)会话工厂
.getCurrentSession()
.get(MyEntity.class,entity.getId(),new LockOptions(LockMode.悲观_-WRITE));
如果(已锁定!=null){
sessionFactory.getCurrentSession().delete(已锁定);
}
}
返回实体;
}

悲观的WRITE mut可以与
get
一起使用,而不是
load
,因为否则会抛出
org.hibernate.ObjectNotFoundException

我花了一些时间研究这个问题,最终明白了会发生什么

悲观写锁尝试“锁定”会话中已加载的实体,但不会从数据库中重新读取对象。调试调用时,我看到
entity==locked
返回
true
(用Java术语)。两个变量都指向同一个实例

要强制hibernate重新加载实体,必须首先将其从会话中删除

下面的代码实现了这一点:

@Transactional
public MyEntity getAndDelete(String prop) {
    List<MyEntity> list = (List<MyEntity>)sessionFactory
        .getCurrentSession()
        .createCriteria(MyEntity.class)
        .add( Restrictions.eq("prop", prop) )
        .list();

    // process the list, and find one entity
    MyEntity entity = findEntity(list);
    if (entity != null) {

        // Remove the entity from the session.
        sessionFactory.getCurrentSession().evict(entity);

        // reload the entity with "select ...for update"
        MyEntity locked = (MyEntity)sessionFactory
            .getCurrentSession()
            .get(MyEntity.class, entity.getId(), new LockOptions(LockMode.PESSIMISTIC_WRITE));
        if (locked != null) {
            sessionFactory.getCurrentSession().delete(locked);
        }
    }
    return entity;
}
@Transactional
公共MyEntity getAndDelete(字符串属性){
列表=(列表)会话工厂
.getCurrentSession()
.createCriteria(MyEntity.class)
.添加(限制条件。等式(“道具”,道具))
.list();
//处理列表,并找到一个实体
MyEntity实体=findEntity(列表);
如果(实体!=null){
//从会话中删除实体。
sessionFactory.getCurrentSession().Recit(实体);
//使用“选择…进行更新”重新加载实体
MyEntity locked=(MyEntity)会话工厂
.getCurrentSession()
.get(MyEntity.class,entity.getId(),new LockOptions(LockMode.悲观_-WRITE));
如果(已锁定!=null){
sessionFactory.getCurrentSession().delete(已锁定);
}
}
返回实体;
}

悲观的写入mut不能与
get
一起使用,而不能与
load
一起使用,因为否则会抛出
org.hibernate.ObjectNotFoundException

会话get现在已被弃用。您知道如何在没有它的情况下重新加载吗?会话get现在已被弃用。你知道如何在没有它的情况下重新加载吗?