Java Spring应用程序中的多实体管理器。重复对象的持久性问题

Java Spring应用程序中的多实体管理器。重复对象的持久性问题,java,spring,hibernate,persistence,entitymanager,Java,Spring,Hibernate,Persistence,Entitymanager,我的Spring组件从客户机获得一个请求,向web服务询问一些数据,并将收到的对象保存到数据库中。 I识别所有对象,仅保存新对象 当客户端在同一时间发出两个或多个相同的请求时(或者由于不同的用户请求,我从web服务接收相同的对象),就会出现问题 要用持久性来描述问题,请参见此处的一些详细信息。对于每个客户端请求,我的组件在一个单独的线程中开始执行,我获得一个新的entityManager,开始一个事务,从web服务接收一个数据,然后在当前事务中使用给定的entityManager标识对象并持久化

我的Spring组件从客户机获得一个请求,向web服务询问一些数据,并将收到的对象保存到数据库中。 I识别所有对象,仅保存新对象

当客户端在同一时间发出两个或多个相同的请求时(或者由于不同的用户请求,我从web服务接收相同的对象),就会出现问题

要用持久性来描述问题,请参见此处的一些详细信息。对于每个客户端请求,我的组件在一个单独的线程中开始执行,我获得一个新的entityManager,开始一个事务,从web服务接收一个数据,然后在当前事务中使用给定的entityManager标识对象并持久化新对象

如果在单独的事务中,我从web服务接收到相同的对象,并且如果它们是尚未在数据库中的新对象,我将无法在未提交的事务中识别它们,因此它们将保留在所有事务中然后所有重复的对象将提交并保存到数据库。

在这种情况下,什么是好的解决方案?即使在不同的事务中,是否有方法正确地识别新对象?或者可以采用什么方法

May beSpring提供了一些管理事务或实体管理器的方法,以便帮助解决此问题

注意。当然,我可以使用数据库工具来避免保存重复的对象,但在这种情况下,这不是一个很好的解决方案

  • 保存前检查数据库中是否存在对象
  • 用于防止重复行,适当处理异常
  • 使用
    @Version
    管理现有实体的并发修改。有关乐观和悲观锁定的更多信息:。相关讨论:和
  • 您可以使用线程锁/同步机制来确保对同一用户的请求将按顺序发生。但是,如果您的服务在多个节点上运行,这将不起作用

    • 因此,我的解决方案如下:

    • 使事务非常小,并分别提交每个对象
    • 在数据库中设置唯一约束,以防止重复 物体。这一点对我们帮助不大,但对第3点是必要的
    • 我们在try-catch块中插入的每个commit()方法。如果我们尝试 在并行事务中提交重复对象,然后我们将收到一个异常,在catch块中,我们可以检查数据库,选择已经存在的对象并进一步处理它
    • 例如:

      boolean reidentifyNeed = false;
      
      try {
      
          DofinService.getEntityManagerThreadLocal().getTransaction().begin();
      
          DofinService.getEntityManagerThreadLocal().persist(entity);
      
          try {
      
              DofinService.getEntityManagerThreadLocal().getTransaction().commit();
      
              //if commit is successfull
              entityIdInDB = (long) entity.getId();
      
              DofinService.getEntityManagerThreadLocal().clear();
      
          } catch (Exception ex) {
      
              logger.error("Error committing " + entity.getClass().getSimpleName() + " in DB. Possibly duplicate object. Will try to re-identify object. Error: " + ex.toString());
      
              reidentifyNeed = true;
      
          }
      
          if(reidentifyNeed){
              //need clear entityManager, because if duplicated object was persisted then during *select* an object flush() method will be executed and it will thrown ConstrainViolationException 
              DofinService.getEntityManagerThreadLocal().clear();
      
              CheckSimilarObject checkSimilarObject = new CheckSimilarObject();
      
              long objectId = checkSimilarObject.checkObject(dofinObject);
      
              logger.warn("Re-identifying was done. EntityId = " + objectId);
      
              entityIdInDB = objectId;
          }
      
      } catch (Exception ex) {
          logger.error("Error persisting and commiting object: " + ex.toString());
      }
      

      请仔细看我的问题。我不需要数据库级别的工具来防止保存重复对象。其中一个原因是,在所描述的数据库约束情况下,在提交两个具有一定数量重复对象的不同事务时,我们将收到来自数据库的错误,其中一个事务将回滚—这不是最佳解决方案。我注意到了这一点,所以我提到了同步。为什么要避免回滚?您认为什么是更好的解决方案?回滚是我们找到的解决方案,比什么都没有好。然而,我们不想浪费用户的时间来潜在地错误请求,因为我们不知道如何管理不同事务中的重复对象。我不认为这在开发系统中是一个独特的情况,所以更好的解决方案可能是。用户将等待任何一种方式。在REST中处理相同的并发请求: