如何保留大量实体(JPA)


问题内容

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

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

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

编辑

这是一个漫长的过程(超过400秒)和我都尝试的解决方案,与persistmerge。两者花费的时间大致相同(459s与443s)。问题是,像这样一个接一个地保存实体是否最佳。据我所知,Hibernate(这是我的JPA提供程序)确实实现了某些缓存/刷新功能,因此我不必为此担心。


问题答案:

JPA API并未为您提供最佳选择。根据您要执行此操作的速度,您将不得不寻找特定于ORM的选项-在您的情况下为休眠状态。

检查事项:

  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<YourEntity> 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的特定批量插入调整。