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
?上面提到的方法不适用于乐观锁定。
答案 0 :(得分:0)
如果您想避免分类merge
,您可以进行“软合并”。相反 - 只需从分离的实例中取出版本并将其设置为托管实例:
Entity managedEntity = entityManager.find(Entity.class, entity.getId());
if (managedEntity == null) {
throw new EntityNotFoundException();
}
managedEntity.setVersion(entity.getVersion());
当然,为了不重复自己,根据您的DAO,存储库等的层次结构,您可以创建一个通用的softMerge
方法,它将加载托管实体,从分离的实例获取版本并设置它是托管的。