Java - JPA - @Version注释

2022-08-31 07:40:48

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

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

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

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


也从以下行:

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

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


答案 1

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

假设一个实体有一个带注释的属性:MyEntityversion

@Entity
public class MyEntity implements Serializable {    

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Version
    private Long version;

    //...
}

更新时,带批注的字段将递增并添加到子句中,如下所示:@VersionWHERE

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

如果子句无法匹配记录(因为同一实体已被另一个线程更新),则持久性提供程序将引发 .WHEREOptimisticLockException

这是否意味着我们应该将我们的版本字段声明为最终字段

不,但您可以考虑使设置者受到保护,因为您不应该称之为。


答案 2

虽然@Pascal答案是完全有效的,但根据我的经验,我发现下面的代码有助于实现乐观锁定:

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

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

    // ...
}

为什么?因为:

  1. 如果用 带批注的字段意外设置为 ,则乐观锁定将不起作用@Versionnull
  2. 由于此特殊字段不一定是对象的业务版本,为了避免误导,我更喜欢将此类字段命名为类似而不是 .optlockversion

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


推荐