Java - JPA - @Version注释

时间:2010-04-03 20:28:03

标签: java jpa jpa-annotations

@Version注释如何在JPA中起作用?

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

  

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

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


同样来自以下几行:

  

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

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

5 个答案:

答案 0 :(得分:175)

  

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

假设实体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

  

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

不,但是你可以考虑让你的setter受到保护,因为你不应该打电话给它。

答案 1 :(得分:26)

虽然@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而不是version
  3. 如果应用程序仅使用 JPA将数据插入数据库,那么第一点并不重要,因为JPA供应商会在创建时强制0 @version字段。但是几乎总是使用普通的SQL语句(至少在单元/集成测试期间)。

答案 2 :(得分:8)

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

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

答案 3 :(得分:2)

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

因此更新实体价值会更安全,更乐观。

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

答案 4 :(得分:0)

只需添加更多信息。

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

佩德罗