在JPA中删除实体时乐观锁定

时间:2015-07-17 12:31:27

标签: 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.remove(managedEntity);
    return !entityManager.contains(managedEntity);
}

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

DELETE FROM db.entity WHERE ((id = ?) AND (version = ?))

如果数据库中的行版本与实体中的行版本冲突,则附加检查AND (version = ?)应导致javax.persistence.OptimisticLockException被抛出。

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

@javax.persistence.Version不同,EntityManager#merge(T entity)不接受分离的实体。将分离的实体传递给EntityManager#remove(Object entity)是错误的。

remove()

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

java.lang.IllegalArgumentException: Entity must be managed to call remove: com.example.Entity[ id=1 ], try merging the detached and try the remove again.

如果实体有关联,则会导致其他问题。

它只留下一个乐观锁定的替代方法,即手动检查行版本,然后手动抛出entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity)); ,这不是人们可能期望的方法。

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

1 个答案:

答案 0 :(得分:0)

如果您想避免分类merge,您可以进行“软合并”。相反 - 只需从分离的实例中取出版本并将其设置为托管实例:

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

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