使用JPA EntityManager进行批量插入操作

39

是否有一种方法可以使用JPA EntityManager进行批量插入?我知道没有直接的方法来实现这一点,但一定有某种方式可以实现该机制。

实际上,对于每个插入操作,它都需要花费我300毫秒,我希望通过使用批量插入而不是单个插入来减少时间。

这是我目前正在使用的用于执行单个插入的代码。

        @PersistenceContext(unitName = "testing")
        EntityManager eM;

        Query querys = this.eM.createNativeQuery(insertQuery);
        for (String s : someList) {
            //setting parameters
            querys.executeUpdate();
        }

提前致谢。

4个回答

22

根据事务是否包含循环,批处理通常已经在您的情况下发生。

JPA将收集所有更新并存储在其L1缓存中,通常在事务提交时将所有内容一次性写入数据库。这与JDBC中的批处理并没有太大区别,因为添加的每个批处理项也都暂时保存在内存中,直到调用更新方法。

潜在的问题是您不能确定JPA是否确实进行了批处理,如果进行了批处理,则是在事务提交时还是在达到一定阈值时进行的。但我发现在实践中,几乎所有情况,特别是涉及如此简单的更新循环的情况下,它确实会进行批处理。

一个问题是即使JPA确实进行了批处理,您仍然可能想要控制批处理大小。其他答案提供的链接文章对此提供了相当有用的信息。

最后,您应该意识到您的L1缓存会在循环中不断增长,因此如果更新数量非常大,请定期清除它。或者,如果您的业务逻辑可以支持,则在多个事务中进行部分更新。例如,项目0至100,000在事务1中进行更新,100,001至200,000在事务2中进行更新,以此类推。


嗨,我现在使用Spring Data JPA,那么你的意思是,如果我在方法内部的循环中更新对象,并且该方法标注了@Transactional,它会自动像JDBC批量更新一样进行批量更新吗? - zhuguowei

21

我知道这是一个相当老的问题,已经有了一个被接受的答案。尽管如此,我想给出一个新的答案来回答这个非常具体的主题“JPA批量插入”。

@PersistenceContext
private EntityManager entityManager;

@Value("${hibernate.jdbc.batch_size}")
private int batchSize;

public <T extends MyClass> Collection<T> bulkSave(Collection<T> entities) {
  final List<T> savedEntities = new ArrayList<T>(entities.size());
  int i = 0;
  for (T t : entities) {
    savedEntities.add(persistOrMerge(t));
    i++;
    if (i % batchSize == 0) {
      // Flush a batch of inserts and release memory.
      entityManager.flush();
      entityManager.clear();
    }
  }
  return savedEntities;
}

private <T extends MyClass> T persistOrMerge(T t) {
  if (t.getId() == null) {
    entityManager.persist(t);
    return t;
  } else {
    return entityManager.merge(t);
  }
}

来源:http://frightanic.com/software-development/jpa-batch-inserts/

这篇文章介绍了如何使用Java Persistence API (JPA)在数据库中批量插入数据。它讨论了使用传统方法和使用JPA的性能差异,并提供了使用JPA进行批量插入的示例代码。

6
我猜我们需要在结束时再次调用flush()clear(),以保存未完成批处理大小的任何剩余对象? - Ram Patra

13

使用JPA执行批量写入是可能的,但它在很大程度上取决于您的持久性提供程序、数据库和JDBC驱动程序的具体实现。例如,这篇文章解释了如何使用EclipseLink JPA 2.3和Oracle数据库启用批量写入(优化#8)。请在您特定的环境中寻找类似的配置参数。


你好,能提供一些代码片段如何在上面提供的代码中使用吗? - Prathap
@Rana如上所述:这取决于您使用的持久性提供程序 - 我无法通过查看代码告诉您,您必须告诉我。 - Óscar López
1
嗨,我正在使用org.eclipse.persistence.jpa.PersistenceProvider。另外,请告诉我是否存在使用批量插入的任何限制。 - Prathap
4
@Rana,所有内容都在链接的文章中,你需要编辑 persistence.xml 文件并添加类似 <property name="eclipselink.jdbc.batch-writing" value="JDBC"/> <property name="eclipselink.jdbc.batch-writing.size" value="1000"/> 的东西。请先花时间阅读文章。 - Óscar López
1
嗨,我已经添加了这个语句,现在我正在寻找有关使用此语句需要注意的任何陷阱的信息。谢谢。 - Prathap

3

请看我的示例 这里 - Lukasz Frankowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接