使用 JPA 的乐观锁定(休眠)

时间:2021-07-20 08:11:49

标签: java hibernate jpa spring-data-jpa optimistic-locking

JPA 乐观锁定不会在我期望的地方抛出 OptimisticLockException/StaleStateException。

这是我的设置: 我正在使用带有弹簧数据包的弹簧靴。所以我的存储库是版本化的,这不应该影响乐观锁定行为。在我的实体中,属性版本 (Long) 用 @Version 注释。我的应用程序由 3 层组成:

  • 持久层
  • 业务层
  • 传输层

为了在层之间映射对象,我使用了 mapstruct。

当传输层的控制器收到请求时,JSON-Payload 被映射到一个业务层对象来处理业务规则。版本始终映射到整个生命周期。 当我到达持久层时,我使用对象的 ID 在我的数据库中找到相应的实体。我的保存方法的签名如下所示:

@Transactional
public Entity saveEntity(BOEntity boEntity){
 Entity e = entityRepository.findById(boEntity.getId());
 entityMapper.updateEntity(boEntity, e);
 entityRepository.save(e);
}

当我的客户端加载相同的实体时,(例如两个浏览器选项卡)它们每个都具有相同版本的实体。在两个客户端中进行更改并保存。 版本包含在 boEntity 对象中并映射到实体中。 由于 findById 调用,实体被管理。 entitymanager 将尝试合并实体,并在两个请求中都成功。

合并第一个请求的实体的状态(与版本1)。 Hibernate 调用 executeUpdate 方法并写入数据库。版本增加到2。 现在,第二个请求以版本 1 的形式交付处于前一状态的实体。调用 save-method 并从持久性上下文中检索实体。它有版本 2,它被版本 1 的 boEntity 对象覆盖。

当 entityManager 现在合并实体时,不会抛出异常。 我的期望是由于旧版本而失败的第二个请求。 不是可以覆盖实体的版本吗?

我已经阅读了很多博客文章,但找不到任何提示。

1 个答案:

答案 0 :(得分:0)

默认的 JPA 乐观锁定机制仅在托管对象被刷新但在此期间被更改时才起作用。你想要的东西必须手动编码。只需将逻辑添加到您的 saveEntity 方法中:

@Transactional
public Entity saveEntity(BOEntity boEntity){
 Entity e = entityRepository.findById(boEntity.getId());
 if (boEntity.getVersion() != e.getVersion()) {
  throw new OptimisticLockException();
 }
 entityMapper.updateEntity(boEntity, e);
 entityRepository.save(e);
}
相关问题