【发布时间】:2015-07-17 12:31:27
【问题描述】:
使用 CMT 的 EJB 中的事务方法,用于删除提供的实体:
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,即使提供的实体将在另一个会话中由另一个用户同时修改,因为它最后一次被客户端(网络或其他)读取,因为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.
在删除like之前直接合并实体,
entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity));
如果实体有关联,则会导致其他问题。
它只留下了乐观锁定的一种替代方法,即手动检查行版本,然后手动抛出javax.persistence.OptimisticLockException,这不是人们可能期望的方法。
长话短说:如果要删除的实体被另一个会话背后修改,如何在删除实体时抛出javax.persistence.OptimisticLockException?上述方法不适用于乐观锁定。
【问题讨论】:
-
合并有什么问题?如果合并了您不想合并的引用实体,则应考虑删除所涉及的级联设置,以便仅合并要删除的实体。否则,请创建您自己的使用 ID 和版本而不是使用 Find 的查询。
-
合并操作会留下EclipseLink 中this 问题中提到的问题。这需要移除级联,但并不总是可行的。在许多其他情况下是必要的。
标签: hibernate jpa eclipselink optimistic-locking