【问题标题】:Optimistic Locking with JPA (Hibernate)使用 JPA 进行乐观锁定(休眠)
【发布时间】:2021-09-27 18:32:48
【问题描述】:

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 交付之前状态的实体。调用保存方法并从持久性上下文中检索实体。它具有版本 2,被版本 1 的 boEntity 对象覆盖。

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

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

【问题讨论】:

  • "不能覆盖实体的版本吗?"它不适用于programmer to touch
  • 如何加载你传入 save 方法的BOEntity boEntity
  • BOEntity 来自请求的有效负载。首先,我有一个传输对象 (DTO),它映射到 BOEntity(包括版本)。 BOEntity 通过 mapstruct 写入到真实的 Entity 中。同样,版本被映射到先前加载的实体(因此实体的版本被覆盖)。假设我的 BOEntity 是我的 DTO(为简单起见)。不是正确的方法,通过 findById 从数据库中加载实体,然后通过设置它的字段来更新实体吗?版本 2 会被旧版本覆盖,Hibernate 会抛出异常?
  • 当我创建一个具有与我想要更新的实体相对应的 ID 的新实体时,我得到了异常。实体然后处于非托管状态。当我调用 save 方法时,抛出异常。

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


【解决方案1】:

默认的 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);
}

【讨论】:

    猜你喜欢
    • 2011-10-18
    • 2016-09-23
    • 1970-01-01
    • 2017-02-06
    • 2011-09-14
    • 2015-06-10
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    相关资源
    最近更新 更多