Java - JPA - @Version 注释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2572566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 09:22:25  来源:igfitidea点击:

Java - JPA - @Version annotation

javajpajpa-annotations

提问by Yatendra Goel

How does @Versionannotation work in JPA?

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

I found various answers whose extract is as follows:

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

JPA uses a version field in your entities to detect concurrent modifications to the same datastore record. When the JPA runtime detects an attempt to concurrently modify the same record, it throws an exception to the transaction attempting to commit last.

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

But I am still not sure how it works.

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



Also as from the following lines:

同样来自以下几行:

You should consider version fields immutable. Changing the field value has undefined results.

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

Does it mean that we should declare our version field as final?

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

采纳答案by Pascal Thivent

But still I am not sure how it works?

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

Let's say an entity MyEntityhas an annotated versionproperty:

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

@Entity
public class MyEntity implements Serializable {    

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Version
    private Long version;

    //...
}

On update, the field annotated with @Versionwill be incremented and added to the WHEREclause, something like this:

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

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

If the WHEREclause fails to match a record (because the same entity has already been updated by another thread), then the persistence provider will throw an OptimisticLockException.

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

Does it mean that we should declare our version field as final

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

No but you could consider making the setter protected as you're not supposed to call it.

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

回答by stefanglase

Every time an entity is updated in the database the version field will be increased by one. Every operation that updates the entity in the database will have appended WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASEto its query.

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

In checking affected rows of your operation the jpa framework can make sure there was no concurrent modification between loading and persisting your entity because the query would not find your entity in the database when it's version number has been increased between load and persist.

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

回答by uudashr

Version used to ensure that only one update in a time. JPA provider will check the version, if the expected version already increase then someone else already update the entity so an exception will be thrown.

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

So updating entity value would be more secure, more optimist.

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

If the value changes frequent, then you might consider not to use version field. For an example "an entity that has counter field, that will increased everytime a web page accessed"

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

回答by G. Demecki

Although @Pascal answer is perfectly valid, from my experience I find the code below helpful to accomplish optimistic locking:

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

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

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

    // ...
}

Why? Because:

为什么?因为:

  1. Optimistic locking won't workif field annotated with @Versionis accidentally set to null.
  2. As this special field isn't necessarily a business version of the object, to avoid a misleading, I prefer to name such field to something like optlockrather than version.
  1. 如果使用注释的字段意外设置为 ,乐观锁定将不起作用@Versionnull
  2. 由于这个特殊字段不一定是对象的商业版本,为了避免误导,我更喜欢将此类字段命名为类似optlock而不是version.

First point doesn't matter if application uses onlyJPA for inserting data into the database, as JPA vendor will enforce 0for @versionfield at creation time. But almost always plain SQL statements are also in use (at least during unit and integration testing).

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

回答by Pedro Borges

Just adding a little more info.

只是添加更多信息。

JPA manages the version under the hood for you, however it doesn't do so when you update your record via JPAUpdateClause, in such cases you need to manually add the version increment to the query.

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

Same can be said about updating via JPQL, i.e. not a simple change to the entity, but an update command to the database even if that is done by hibernate

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

Pedro

佩德罗