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

标签 java hibernate jpa datanucleus optimistic-locking

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

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

    @Column
    private String name;

    @Version
    int version;

    // Getters + setters
}

假设我有一个服务(REST API 或类似的东西),允许用户检索有关该实体的信息。它返回 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 中存在错误,其中之一不遵循 JPA 规范,要么规范没有明确指定它应该如何工作?

我试图找到这个问题的明确答案,但未能成功。有人可以确认,根据 JPA 规范,在使用外部提供的版本号更新实体时,乐观锁定应该如何工作?

最佳答案

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

JPA 2.0 规范摘录:

The Version field or property is used by the persistence provider to perform optimistic locking. It is accessed and/or set by the persistence provider in the course of performing lifecycle operations on the entity instance. An entity is automatically enabled for optimistic locking if it has a property or field mapped with a Version mapping. An entity may access the state of its version field or property or export a method for use by the application to access the version, but must not modify the version value[34]. With the exception noted in section 4.10, only the persistence provider is permitted to set or update the value of the version attribute in the object.

关于更新过程:您通常会从 Rest Interface 检索对象的 ID 以及要更改的数据。您将两者传递给 Service,在其中告诉 EntityManager 获取具有给定 ID 的实体,更新该实体的数据,并告诉 EntityManager 立即将其保存回来。这个过程并不是一成不变的,但在大多数情况下大致就是这样完成的。

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

关于java - JPA 乐观锁定规范是否支持根据客户端提供的版本进行验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50420000/

相关文章:

java - 如何以编程方式创建其中包含 EditText 的选项卡?

java - Hibernate,如果拥有的实体相同,则使用已保存在数据库中的实体与拥有方链接,而不是创建一个新实体

java - 比较 Java 中 Postgresql 中的时间戳日期

java - EntityManager.remove() 不抛出预期的异常

java - 如何使用 visualvm 分析应用程序启动

java - 错误 : Path must include project and resource name:/(org. apache.maven.plugins :maven-jar-plugin:2. 4:jar:default-jar:package)

Java Applet的URLConnection到PHP没有效果

java - 如何在 hibernate 中映射自动增量字段?

mysql - hibernate连接表mysql

java - 调用 EntityManager.persist() 时出现未知实体