Java JPA乐观锁定规范是否支持根据客户端提供的版本进行验证

Java JPA乐观锁定规范是否支持根据客户端提供的版本进行验证,java,hibernate,jpa,datanucleus,optimistic-locking,Java,Hibernate,Jpa,Datanucleus,Optimistic Locking,假设我有一个定义如下的实体: @Entity public class MyEntity { @Id @GeneratedValue private Integer id; @Column private String name; @Version int version; // Getters + setters } 假设我还有一个服务(RESTAPI或类似的东西),允许用户检索关于这个实体的信息。它返回ID、当前名称和当

假设我有一个定义如下的实体:

@Entity
public class MyEntity {
    @Id
    @GeneratedValue
    private Integer id;

    @Column
    private String name;

    @Version
    int version;

    // Getters + setters
}
假设我还有一个服务(RESTAPI或类似的东西),允许用户检索关于这个实体的信息。它返回ID、当前名称和当前版本。还有另一项服务允许用户更新实体的名称。它接受ID、更新名称和版本作为输入参数。因此,可以通过创建新对象并使用合并来更新实体:

public MyEntity update(EntityManager em, int id, String name, int version) {
    MyEntity entity = new Entity();
    entity.setId(id);
    entity.setName(name);
    entity.setVersion(version);
    return em.merge(entity);
}
或者,可以通过从数据库检索并仅更新相关字段来更新:

public MyEntity update(EntityManager em, int id, String name, int version) {
    MyEntity entity = em.find(MyEntity.class, id);
    entity.setName(name);
    entity.setVersion(version);
    return entity;
}
我的测试告诉我,在Hibernate 5.3中,如果提供的版本与数据库中的版本不匹配,第一个场景将抛出OptimisticLockException(消息
行被另一个事务更新或删除(或者未保存的值映射不正确)
)。但是,第二个场景工作正常,无论提供的版本如何,名称都会更新

我也在DataNucleus 5.1.9中尝试过这一点,但两种情况下都不会引发异常,并且无论在这两种情况下提供的版本如何,名称都会更新

所以我猜要么Hibernate或者DataNucleus中有一个bug,其中一个没有遵循JPA规范,要么规范没有明确说明应该如何工作


我曾试图找到一个明确的答案,但未能做到这一点。有人能确认,根据JPA规范,当使用外部提供的版本号更新实体时,乐观锁定应该如何工作吗?

eek,外部设置@version字段?在大多数情况下,这可能会导致冲突,因为它不应该由开发人员设置。它由持久性提供程序专门管理。您不需要
getter
setter
来访问
版本

JPA2.0规范的摘录:

持久性提供程序使用版本字段或属性来 执行乐观锁定。它由用户访问和/或设置 执行生命周期操作过程中的持久性提供程序 在实体实例上。实体将自动为其启用 乐观锁定,如果它具有与版本映射的属性或字段 映射。实体可以访问其版本字段的状态或 属性或导出方法,以供应用程序用于访问 版本,但不得修改版本值[34]。例外 在第节中注明 4.10中,仅允许持久性提供程序设置或更新对象中版本属性的值

关于更新过程:通常从Rest接口检索对象的ID和要更改的数据。您将两者传递到
服务
,在该服务中,您告诉
实体管理器
获取具有给定ID的实体,更新该实体上的数据,并告诉
实体管理器
立即将其存回。这个过程不是刻在石头上的,但大体上大多数情况下都是这样


您的实体上的
setID()
setVersion()
方法都很可能是不好的做法。

您的假设是错误的;你不能设定那个。为什么不看看在persist/merge上调用的SQL呢?然后你可能会看到有用的信息