【问题标题】:Hibernate unexpectedly issues INSERT instead of throwing the javax.persistence.OptimisticLockException, when a nonexistent entity is passed to merge()当不存在的实体传递给 merge() 时,Hibernate 意外发出 INSERT 而不是抛出 javax.persistence.OptimisticLockException
【发布时间】:2023-12-29 12:45:01
【问题描述】:

客户端应用程序提供了一个陈旧的实体,该实体将被 Hibernate 合并。举个很简单的例子。

public Entity update(Entity entity) {
    return entityManager.contains(entity) ? entity : entityManager.merge(entity);
}

Entity 是一个分离的、陈旧的实体,例如,由 Web 应用程序提供。该方法在活动的 JTA 事务(或本地资源)中执行。

已通过在给定实体中引入@Version 字段来启用乐观锁定。

当要合并的实体已经被删除时,javax.persistence.OptimisticLockException 预计会被抛出,但不会发生。 Hibernate 执行INSERT,这完全出乎意料。插入一个过时的实体而不是抛出 javax.persistence.OptimisticLockException 是违反锁定的。

“插入或更新”是一个单独的故事,如果将过时或已删除(不存在)的实体传递给merge(),则应通过抛出javax.persistence.OptimisticLockException 暂停该故事,如果实施了乐观锁定。

EclipseLink 会按预期抛出javax.persistence.OptimisticLockException,以防将过时或已删除/不存在的实体传递给merge()

当一个陈旧或不存在的实体被传递给merge()时,有没有办法让Hibernate抛出javax.persistence.OptimisticLockException

我希望persistence.xml 中应该有一些可配置的属性以将其应用于全局应用程序范围或注释以将其应用于特定实体。

我目前使用的是 Hibernate 5.0.5 final。


更新到 Hibernate 5.0.6 final。

【问题讨论】:

  • 这是一个长期存在的 Hibernate 错误。你可以投票给它:hibernate.atlassian.net/browse/HHH-1661
  • 这个问题大约有十年的历史了。
  • 我认为,应该创建一个新的、新鲜的问题。该问题报告不太可能被考虑在内,因为它已经很老了。这是一个不能掉以轻心的严重bug,需要尽快修复。
  • 它已针对 Hibernate 5 进行了更新,因此在进行大型 JIRA 清理时保留在未解决的错误中,它是精确的、有投票的和可重现的测试用例。打开一个新的相同错误将消除该错误或注意力,或者被标记为重复。

标签: hibernate jpa merge optimistic-locking


【解决方案1】:

尝试 EntityManager.refresh 代替 EntityManager.merge,并验证实体是否有 id 值,如果是则设置新值,如果没有,则在 EntityManager.merge 之后,实体已被删除

类似的东西

public Entity update(Entity entity) {

    entityManager.refresh(entity);

    if (entity.getId() != null) {
        // my entity is in database
        // set my changes in entity
        return entityManager.merge(entity);
    } else {
        // my entity has been deleted
        return null;
    }
}

【讨论】:

    最近更新 更多