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; // ... }
为什么? 因为:
- 如果使用
@Version
注释的字段意外设置为null
乐观locking将不起作用 。 - 由于这个专业领域不一定是对象的商业版本,为了避免误导,我更愿意将这样的领域命名为
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时,它不会这样做,在这种情况下,你需要手动将版本增量添加到查询中。
佩德罗