Java – JPA – @Version注释

@Version注解如何在JPA中工作?

我find了各种答案,其摘录如下:

JPA在您的实体中使用版本字段来检测对同一数据存储logging的并发修改。 当JPA运行时检测到试图同时修改相同的logging时,它会向最后提交的事务抛出一个exception。

但我仍然不确定它是如何工作的。


还从以下几行开始:

你应该考虑版本字段不可变。 更改字段值有未定义的结果。

这是否意味着我们应该宣布我们的版本字段是final

但是我还不确定它是如何工作的?

比方说一个实体MyEntity有一个带注释的version属性:

 @Entity public class MyEntity implements Serializable { @Id @GeneratedValue private Long id; private String name; @Version private Long version; //... } 

更新时,使用@Version注释的字段将被增加并添加到WHERE子句中,如下所示:

 UPDATE MYENTITY SET ..., VERSION = VERSION + 1 WHERE ((ID = ?) AND (VERSION = ?)) 

如果WHERE子句与logging匹配失败(因为同一个实体已被另一个线程更新),那么持久性提供者将抛出一个OptimisticLockException

这是否意味着我们应该宣布我们的版本字段是最终的

不,但你可以考虑让二传手保护起来,因为你不应该叫它。

尽pipe@Pascal答案是完全有效的,但从我的经验来看,下面的代码有助于实现乐观locking:

 @Entity public class MyEntity implements Serializable { // ... @Version @Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false) private long version = 0L; // ... } 

为什么? 因为:

  1. 如果使用@Version注释的字段意外设置为null乐观locking将不起作用
  2. 由于这个专业领域不一定是对象的商业版本,为了避免误导,我更愿意将这样的领域命名为optlock而不是version

如果应用程序使用JPA将数据插入数据库,则第一点并不重要,因为JPA供应商将在创build时为@version字段强制执行0 。 但是几乎总是普通的SQL语句也在使用中(至less在单元/集成testing中)。

每次在数据库中更新实体时,版本字段将被增加1。 更新数据库中的实体的每个操作都将在其查询中附加WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASE

在检查受影响的操作行时,jpa框架可以确保在加载和保持实体之间没有并发修改,因为在加载和保持之间版本号增加时,查询不会在数据库中find您的实体。

用来确保一次只更新一次的版本。 JPA提供程序将检查版本,如果预期的版本已经增加,那么其他人已经更新了实体,所以会抛出exception。

所以更新实体价值会更安全,更乐观。

如果值频繁变化,那么你可能会考虑不使用版本字段。 举个例子,“一个具有反场的实体,每次访问一个网页都会增加”

只需添加一些信息。

JPA为你pipe理版本,但是当你通过JPAUpdateClause()更新你的logging时,它不会这样做,在这种情况下,你需要手动将版本增量添加到查询中。

佩德罗