11

环境:

我有那个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()在两种情况下都返回相同的值,即使在第二次更新中,user.version第一次编辑已经更新了。

我错过了什么吗?

EntityManager产生了@RequestScoped(所以当我尝试合并时我在两个不同的EntityManagers 上......)。

我之前尝试entityManager.lock(user, LockModeType.OPTIMISTIC_FORCE_INCREMENT)entityManager.merge(...)如此处所述),但没有帮助。

我正在使用 Seam 3 和 JBoss 7.0.2.Final(它使用 Hibernate 4)。

4

3 回答 3

7

我只是对此做了更多的研究。

不允许根据 JPA 规范修改版本字段:

JPA 2.0 最终规范,第 3.4.2 节:

实体可以访问其版本字段或属性的状态或导出供应用程序使用的方法来访问版本,但不得修改版本值。除了 4.10 节中提到的例外,只有持久性提供者被允许设置或更新对象中版本属性的值。

注意:第 4.10 节是指忽略版本属性的批量更新。

于 2013-06-28T09:51:04.873 回答
6

实际上我已经找到了一种方法来做到这一点......但我认为它并不是很有效(因为还有 1 个 SELECT 请求)。

User user = entityManager.find(User.class, userId)
user.setLogin(form.getLogin());
user.setVersion(form.getVersion());
user.setUserId(form.getUserId());

entityManager.detach(user);
entityManager.merge(user);

有了entityManager.detach(user),休眠现在使用我设置version的值而不是它自己复制的某处值...

于 2012-02-15T18:49:43.200 回答
1

找到了另一种手动触发乐观锁定的方法。我们可以将缓存的 Hibernate 版本与实体中的版本进行比较。我正在使用 spring data JPA,并添加了 ff. 到存储库保存实现:

EntityEntry entityEntry = entityManager
  .unwrap(SessionImplementor.class)
  .getPersistenceContext()
  .getEntry(entity);

//checked if a cached entry is present
if (entityEntry != null) {

  //Compare cached version with the one in the entity
  if (!Objects.equals(entityEntry.getVersion(), classMetadata.getVersion(entity))) {
    throw new ObjectOptimisticLockingFailureException();
  }
}
于 2018-11-06T04:14:05.363 回答