我有2个并发线程同时输入(Spring)事务服务。删除实体时避免StaleObjectStateException
使用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;
}
如果在同一时间两个线程传递相同的参数,都将“发现”同一实体的两个将调用delete
。其中一人在会议结束时将失败投掷org.hibernate.StaleObjectStateException
。
我想这两个线程都会返回实体,不会抛出异常。为了实现这一点,我试图锁定(与“SELECT ... FOR UPDATE”),删除它之前的实体,如下:
@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()
根据休眠的API以来,如果已经在会话中,get会返回实体,而加载应该重新读取它。
如果两个线程同时进入上述方法,则其中一个线程阻塞锁定阶段,并且当第一个线程关闭事务时,第二个线程会唤醒org.hibernate.StaleObjectStateException
。为什么?
为什么锁定的负载不只是返回null?我怎么能做到这一点?
Session get现已弃用。你知道如何在没有它的情况下重新加载吗? – Alison