如何坚持很多实体(JPA)

我需要处理一个CSV文件,并为每个记录(行)保留一个实体。 现在,我这样做:

while ((line = reader.readNext()) != null) { Entity entity = createEntityObject(line); entityManager.save(entity); i++; } 

其中save(Entity)方法基本上只是一个EntityManager.merge()调用。 CSV文件中大约有20,000个实体(行)。 这是一种有效的方法吗? 这似乎很慢。 使用EntityManager.persist()会更好吗? 这种解决方案有何缺陷?

编辑

这是一个漫长的过程(超过400s),我尝试了两种解决方案, persistmerge 。 两者都需要大约相同的时间才能完成(459s vs 443s)。 问题是如果逐个保存实体是最佳的。 据我所知,Hibernate(我的JPA提供程序)确实实现了一些缓存/刷新function,所以我不必担心这一点。

JPA API没有为您提供使其达到最佳的所有选项。 根据您想要的速度,您将不得不寻找特定于ORM的选项 – 在您的情况下使用Hibernate。

要检查的事项:

  1. 检查您是否正在使用单笔交易(是的,显然您确定了这一点)
  2. 检查您的JPA提供程序(Hibernate)是否正在使用JDBC批处理API(请参阅:hibernate.jdbc.batch_size)
  3. 检查是否可以绕过获取生成的密钥(取决于db / jdbc驱动程序从中获得多少好处 – 请参阅:hibernate.jdbc.use_getGeneratedKeys)
  4. 检查是否可以绕过级联逻辑(只有最小的性能优势)

所以在Ebean ORM中这将是:

  EbeanServer server = Ebean.getServer(null); Transaction transaction = server.beginTransaction(); try { // Use JDBC batch API with a batch size of 100 transaction.setBatchSize(100); // Don't bother getting generated keys transaction.setBatchGetGeneratedKeys(false); // Skip cascading persist transaction.setPersistCascade(false); // persist your beans ... Iterator it = null; // obviously should not be null while (it.hasNext()) { YourEntity yourEntity = it.next(); server.save(yourEntity); } transaction.commit(); } finally { transaction.end(); } 

哦,如果你通过原始JDBC执行此操作,则跳过ORM开销(减少对象创建/垃圾收集等) – 所以我不会忽略该选项。

所以,是的,这不能回答您的问题,但可能有助于您搜索更多ORM特定的批量插入调整。

我认为这样做的一种常见方式是交易。 如果您开始新事务然后持久存储大量对象,则在提交事务之前,它们实际上不会插入到数据库中。 如果您要提交大量项目,这可以提高效率。

查看EntityManager.getTransaction

您可以使用经典的SQL Insert语句将它们直接写入数据库。

@see EntityManager.createNativeQuery

为了使它更快,至少在Hibernate中,你会在一定数量的插入后执行flush()和clear()。 我已经为数百万条记录做了这种方法并且它有效。 它仍然很慢,但它比不这样做要快得多。 基本结构是这样的:

 int i = 0; for(MyThingy thingy : lotsOfThingies) { dao.save(thingy.toModel()) if(++i % 20 == 0) { dao.flushAndClear(); } }