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 现在合并实体时,不会抛出异常。 我的期望是由于旧版本而失败的第二个请求。 不是可以覆盖实体的版本吗?
我已经阅读了很多博客文章,但找不到任何提示。
答案 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);
}