Hibernate如何有效地处理100.000+实体更新

时间:2015-08-12 13:27:16

标签: hibernate postgresql java-ee

我有几个客户希望使用CSV文件更新他们的数据,典型客户的文件有1.000到20,000行。

解析行后,我将新的新数据合并到现有实体中。已修改的所有实体都使用批量保存保存:

public void batchSaveOrUpdate(List<Item> items) {
    Transaction transaction = session.beginTransaction();
    List<Item> itemsToEvict = new ArrayList<>();

    int count = 0;
    for (Item item : itemss) {
        session.saveOrUpdate(item);
        itemsToEvict.add(item);

        if (count++ % 25 == 0) {
            session.flush();
            itemsToEvict.forEach(session::evict);
            itemsToEvict.clear();
        }
    }

    transaction.commit();
    session.flush();
}

适用于最多25.000行的正常导入,但现在我有一个客户,哪个CSV文件包含多达600.000行。 即使在确定已修改的项目之后,仍有100,000个实体可以立即更新。 由于一段时间后WildFly会收到所有交易,因此大客户的所有进口都会失败。 我已经将事务超时时间增加到一小时,并且进一步增加对我来说无法解决。

此时我可以做些什么来增加hibernate更新预先性能?

3 个答案:

答案 0 :(得分:1)

确保您实际使用的是批处理。正确配置与批次相关的属性:

<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>

我已将jdbc.batch_size设置为100;在您刷新会话之前,此值应与处理项目的计数相匹配(在您的情况下为25;或许您应该尝试更多,例如100)。

此外,您正在明确驱逐项目。如果Item与其他实体相关联,并且在关联上未指定级联类型ALLDETACH,则驱逐将不会级联到相关实体,并且它们将消耗大量堆,因为Hibernate会将它们保留在持久化上下文(会话)中,因此如果存在数十万个应用程序性能,则会显着降低应用程序性能。

确保分离(逐出)整个对象图,或清除整个会话并阅读下一个要处理的项目块。

答案 1 :(得分:1)

您可以尝试编写自己的存储过程。 Hibernate不是最适合您的需求..

答案 2 :(得分:1)

首先,CopyManager是将CVS复制到postgres的最有效方法。可能是您应该创建一些临时表,然后复制CSV然后执行一组插入/更新SQL语句。获取PGConnection和CopyManager可能很棘手。例如。如果您使用c3p0连接池,则无法实现。

根据Chapter 4. Batch Processing

也很重要
  

如果使用身份标识符生成器,​​Hibernate会透明地禁用JDBC级别的插入批处理。