Hibernate JPA中删除实体时的乐观锁定

Hibernate JPA中删除实体时的乐观锁定,hibernate,jpa,eclipselink,optimistic-locking,Hibernate,Jpa,Eclipselink,Optimistic Locking,EJB中使用CMT的事务方法,用于删除提供的实体: public boolean delete(Entity entity) { Entity managedEntity = entityManager.find(Entity.class, entity.getId()); if (managedEntity == null) { throw new EntityNotFoundException(); } entityManager.remo

EJB中使用CMT的事务方法,用于删除提供的实体:

public boolean delete(Entity entity) {
    Entity managedEntity = entityManager.find(Entity.class, entity.getId());

    if (managedEntity == null) {
        throw new EntityNotFoundException();
    }

    entityManager.remove(managedEntity);
    return !entityManager.contains(managedEntity);
}
关联的客户端提供的实体是分离的实体。
entityManager.remove()
操作生成一个
DELETE
DML语句,如下所示

从db.entity中删除,其中((id=?)和(version=?)
如果数据库中的行版本与实体中的行版本冲突,则附加检查
和(version=?)
应导致抛出
javax.persistence.OptimisticLockException

尽管如此,这不会抛出
javax.persistence.OptimisticLockException
,即使提供的实体将由另一个用户在另一个会话中同时修改,因为它最后一次被客户端读取(web或其他),因为
find()
方法在另一个事务中获取具有更新行版本的实体(旧的/过时的行版本(由
@javax.persistence.version标记)仅包含在作为方法参数提供的分离实体中)

EntityManager#merge(T实体)
不同,
EntityManager#remove(Object实体)
不接受分离的实体。将分离的实体传递到
remove()
时出错

在删除like之前直接合并实体

entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity));
如果实体具有关联,则会导致其他问题

对于乐观锁定,它只剩下一种选择,即手动检查行版本,然后手动抛出
javax.persistence.OptimisticLockException
,这不是我们所期望的方法


长话短说:如果要删除的实体被另一个会话在背后修改,如何在删除实体时抛出
javax.persistence.OptimisticLockException
?上述方法不适用于乐观锁定。

如果要避免分类
合并
,您可以改为执行“软合并”-只需从分离的实例获取版本并将其设置为托管版本:

Entity managedEntity = entityManager.find(Entity.class, entity.getId());
if (managedEntity == null) {
    throw new EntityNotFoundException();
}
managedEntity.setVersion(entity.getVersion());

当然,为了避免重复,根据DAO、存储库等的层次结构,您可以创建一个通用的
softMerge
方法,该方法将加载托管实体,从分离的实例中获取版本并将其设置为托管实体。

合并有什么问题?如果合并了不希望合并的引用实体,则应考虑删除涉及的级联设置,以便只合并要删除的实体。否则,创建自己的查询,使用ID和版本而不是使用查找。合并操作会留下EclipseLink中提到的问题。这需要删除级联,但并不总是可能的。在许多其他情况下,这是必需的。
@javax.persistence.Version
字段的setter方法被声明为
protected
,以防止对Version字段进行潜在的意外更改。为True,但您希望立即显式更改它。:)作为一种替代方法,generic
softMerge
方法可以使用反射来设置它,以便它对所有实体都有效。由于
softMerge
将是框架的一部分,因此可以使用反射。
Entity managedEntity = entityManager.find(Entity.class, entity.getId());
if (managedEntity == null) {
    throw new EntityNotFoundException();
}
managedEntity.setVersion(entity.getVersion());