假设我有一个定义如下的实体:
@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/