批量插入现有数据:防止JPA在每次插入之前执行选择

时间:2017-07-12 09:59:37

标签: java spring hibernate jpa

我正在使用一个使用JPA(Hibernate)作为持久层的Spring Boot应用程序。

我目前正在实施迁移功能。我们基本上将系统的所有现有实体转储到XML文件中。此导出也包括实体的ID。

我遇到的问题位于另一边,重新导入现有数据。在此步骤中,XML再次转换为Java对象并持久保存到数据库中。

尝试保存实体时,我使用merge类的EntityManager方法,该方法有效:一切都已成功保存。

然而,当我打开Hibernate的查询日志记录时,我看到在每个插入查询之前,执行一个select查询以查看具有该id的实体是否已经存在。这是因为实体已经拥有我提供的ID。

我理解这种行为,它实际上是有道理的。但我确信这些ID不会存在,因此选择对我的情况没有意义。我节省了数千条记录,这意味着对大型表格进行了数千次选择查询,这大大减慢了导入过程。

我的问题:有没有办法在插入"之前检查实体是否存在?关闭?

其他信息:

当我使用entityManager.persist()而不是合并时,我得到了这个例外:

  

org.hibernate.PersistentObjectException:传递给的分离实体   坚持

为了能够使用提供的/提供的id,我使用这个id生成器:​​

@Id
@GeneratedValue(generator = "use-id-or-generate")
@GenericGenerator(name = "use-id-or-generate", strategy = "be.stackoverflowexample.core.domain.UseIdOrGenerate")
@JsonIgnore
private String id;

发电机本身:

public class UseIdOrGenerate extends UUIDGenerator {

  private String entityName;

  @Override
  public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
      entityName = params.getProperty(ENTITY_NAME);
      super.configure(type, params, serviceRegistry);
  }

  @Override
  public Serializable generate(SessionImplementor session, Object object) 
  {
        Serializable id = session
            .getEntityPersister(entityName, object)
            .getIdentifier(object, session);

      if (id == null) {
        return super.generate(session, object);
      } else {
        return id;
      }
  }
}

2 个答案:

答案 0 :(得分:2)

如果您确定永远不会更新数据库中的任何现有条目,并且所有实体都应该总是刚刚插入,那么我会选择<%= debug @article %>操作而不是persist

每次更新

在这种情况下(id字段被设置为自动生成),唯一的方法是从id字段中删除生成注释并将配置保留为:

merge

所以基本上设置id以便始终手动分配。然后,即使id存在,持久性提供程序也会将您的实体视为瞬态。这意味着@Id @JsonIgnore private String id; 将起作用,并且不会生成额外的选择。

答案 1 :(得分:1)

我不确定我是否填写了身份证。如果您在应用程序端填写它,请检查answer here。我在下面复制了它:

以下是使用Spring Data存储库时使用的Spring SimpleJpaRepository的代码:

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

它执行以下操作:

  

默认情况下,Spring Data JPA会检查给定实体的identifier属性。如果identifier属性为null,则该实体将被假定为new,否则将被假定为new。

Link to Spring Data documentation

因此,如果你的某个实体的ID字段不为null,那么Spring将使Hibernate进行更新(之前是SELECT)。

您可以通过同一文档中列出的两种方式覆盖此行为。一种简单的方法是让你的实体实现Persistable(而不是Serializable),这将使你实现方法“isNew”。