繁体   English   中英

Java - JPA - @Version 注释

[英]Java - JPA - @Version annotation

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

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

JPA 使用实体中的版本字段来检测对同一数据存储记录的并发修改。 当 JPA 运行时检测到同时修改同一记录的尝试时,它会向尝试最后提交的事务抛出异常。

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


同样来自以下几行:

您应该考虑版本字段不可变。 更改字段值会产生未定义的结果。

这是否意味着我们应该将 version 字段声明为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子句无法匹配记录(因为同一实体已被另一个线程更新),则持久性提供程序将抛出OptimisticLockException

这是否意味着我们应该将我们的 version 字段声明为 final

不,但您可以考虑使 setter 受保护,因为您不应该调用它。

尽管@Pascal 的回答是完全有效的,但根据我的经验,我发现以下代码有助于实现乐观锁定:

@Entity
public class MyEntity implements Serializable {    
    // ...

    @Version
    @Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false)
    private long version = 0L;

    // ...
}

为什么? 因为:

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

如果应用程序使用 JPA 将数据插入数据库,那么第一点并不重要,因为 JPA 供应商将在创建时为@version字段强制执行0 但几乎总是使用简单的 SQL 语句(至少在单元和集成测试期间)。

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

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

用于确保一次仅更新一次的版本。 JPA 提供程序将检查版本,如果预期版本已经增加,那么其他人已经更新了实体,因此将引发异常。

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

如果值频繁变化,那么您可以考虑不使用版本字段。 例如“具有计数器字段的实体,每次访问网页时都会增加”

只是添加更多信息。

JPA 为您管理引擎盖下的版本,但是当您通过JPAUpdateClause更新记录时它不JPAUpdateClause ,在这种情况下,您需要手动将版本增量添加到查询中。

关于通过 JPQL 更新也可以这样说,即不是对实体的简单更改,而是对数据库的更新命令,即使这是通过休眠完成的

佩德罗

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM