如何使用 Hibernate 4 手动设置 @Version 字段?
环境:
我有一个User
实体:
@Entity
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userId;
@Version
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "VERSION", length = 19)
private Date version;
@Column(nullable = false, length = 20)
private String login;
// Getters and Setters
}
我有一个列出用户的搜索页面,然后我单击一个用户来编辑它(给出其userId 在 URL 中)。
在编辑表单中,我将该实体的字段存储在服务器上,当我保存用户时,我会这样做:
User user = entityManager.find(User.class, userId)
user.setLogin(form.getLogin());
user.setVersion(form.getVersion());
user.setUserId(form.getUserId());
entityManager.merge(user);
问题:
因此,如果我正确理解了 Hibernate 的乐观锁定,如果我在中打开 2 个选项卡我的浏览器编辑同一用户,然后更新第一个选项卡上的登录信息,然后第二个选项卡上的登录信息,我应该有一个OptimisticLockException 我不应该吗?
实际上,我的应用程序并非如此...我验证了,form.getVersion()在两种情况下都返回相同的值,即使在第二次更新中,用户.version 已由第一次编辑更新。
我错过了什么吗?
EntityManager
是由 @RequestScoped
生成的(因此,当我尝试合并时,我处于两个不同的 EntityManager
上...)。
我尝试在 entityManager.merge(...)
(如此处所述),但没有帮助。
我将 Seam 3 与 JBoss 7.0.2.Final(使用 Hibernate 4)一起使用。
Environment:
I have that User
entity :
@Entity
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userId;
@Version
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "VERSION", length = 19)
private Date version;
@Column(nullable = false, length = 20)
private String login;
// Getters and Setters
}
I have a search page which lists users, then I click on a user to edit it (giving its userId
in the URL).
In the edit form, I store on the server the fields of that entity and when I save my User I do this :
User user = entityManager.find(User.class, userId)
user.setLogin(form.getLogin());
user.setVersion(form.getVersion());
user.setUserId(form.getUserId());
entityManager.merge(user);
Question:
So if I correctly understood optimistic locking with Hibernate, if I open 2 tabs in my browser to edit the same user, then update the login on the first tab, and then the login on the second tab, I should have an OptimisticLockException
shouldn't I ?
Actually, this is not the case on my application... I verified, the form.getVersion()
return the same value in both case, even if that in the second update, the user.version
has been updated by the first edit.
Am I missing something ?
The EntityManager
is produced @RequestScoped
(so I'm on two different EntityManager
s when I try to merge...).
I've tried to do a entityManager.lock(user, LockModeType.OPTIMISTIC_FORCE_INCREMENT)
before entityManager.merge(...)
(as said here), but it didn't help.
I'm using Seam 3 with JBoss 7.0.2.Final (which uses Hibernate 4).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我刚刚对此做了一些更多的研究。
根据 JPA 规范,不允许修改版本字段:
JPA 2.0 Final Spec,Section 3.4.2:
注意:4.10节指的是忽略版本属性的批量更新。
I just did some more research on this.
It is not allowed to modify the version field according to the JPA spec:
JPA 2.0 Final Spec, Section 3.4.2:
Note: Section 4.10 refers to batch updates which ignore the version attribute.
实际上我已经找到了一种方法来做到这一点...但我认为它并不是真正有效(因为还有 1 个 SELECT 请求)。
通过
entityManager.detach(user)
,hibernate 现在使用我设置的version
值,而不是它自己复制到某处的值...Actually I've found a way to do that... but I think it's not really efficient (because there is 1 more SELECT request).
With
entityManager.detach(user)
, hibernate now uses my settedversion
value instead of its own copied somewhere value...找到了另一种手动触发乐观锁定的方法。我们可以将缓存的 Hibernate 版本与实体中的版本进行比较。我正在使用 spring data JPA,并添加了 ff.到存储库保存实现:
Found another way of triggering optimistic locking manually. We can compare the cached Hibernate version with the version in the entity. I'm using spring data JPA, and added the ff. to the repository save implementation: