假设我有一个如下定义的实体:
htmlOutput("modelParameters")
假设我还有一个服务(REST API或类似的东西),它允许用户检索有关该实体的信息。它返回ID,当前名称和当前版本。还有另一种服务允许用户更新实体的名称。它接受ID,更新名称和版本作为输入参数。因此,可以通过创建新对象并使用合并来更新实体:
@Entity
public class MyEntity {
@Id
@GeneratedValue
private Integer id;
@Column
private String name;
@Version
int version;
// Getters + setters
}
或者,可以通过从数据库中检索并仅更新相关字段来更新它:
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);
}
我的测试告诉我,在Hibernate 5.3中,如果提供的版本与数据库中的版本不匹配,则第一个场景将抛出OptimisticLockException(带有消息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;
}
)。但是,第二种情况正常,无论提供的版本如何,名称都会更新。
我也尝试过使用DataNucleus 5.1.9,并且两种方案都不会引发异常,并且无论两种情况下提供的版本如何,名称都会更新。
所以我想Hibernate或DataNucleus中有一个错误,其中一个没有遵循JPA规范,或者规范没有明确说明它应该如何工作?
我试图找到一个确定的答案,但无法这样做。根据JPA规范,有人可以确认在使用外部提供的版本号更新实体时应该如何乐观锁定工作吗?
答案 0 :(得分:1)
Eeeek,在外部设置@Version字段?在大多数情况下,这可能会导致冲突,因为它不应该由开发人员设置。它由Persistence Provider专门管理。您不需要getter
或setter
来访问version
。
摘自JPA 2.0规范:
持久性提供程序使用Version字段或属性 执行乐观锁定。它由访问和/或设置 执行生命周期操作过程中的持久性提供程序 在实体实例上。将自动启用实体 乐观锁定,如果它具有与版本映射的属性或字段 映射。实体可以访问其版本字段的状态或 属性或导出应用程序访问的方法 版本,但不得修改版本值[34]。有这个特例 在章节中提到 4.10,只允许持久性提供程序设置或更新对象中version属性的值。
关于更新过程:您通常会从Rest Interface中检索对象的ID和要更改的数据。您将两者都传递给Service
,在其中您告诉EntityManager
获取具有给定ID的实体,更新该实体上的数据,并告诉EntityManager
将其保存回来远。这个程序并不是一成不变的,而是大致说明在大多数情况下它是如何完成的。
你的网站上的setID()
和setVersion()
方法都很可能是不好的做法。