使用无状态会话批量插入/更新 - Hibernate

时间:2016-06-24 10:40:10

标签: java hibernate

我要求在3个表中插入/更新超过15000行。这就是45k的总插入量。

我在网上阅读之后在休眠中使用了Statelesssession,因为它没有上下文缓存,所以它最适合批量处理。

session = sessionFactory.openStatelessSession;
for(Employee e: emplList) {
  session.insert(e);
}
transcation.commit;

但是这段代码需要一个多小时才能完成。

有没有办法一次性保存所有实体对象? 保存整个集合而不是逐个进行?

编辑:还有其他框架可以提供快速插入吗?

干杯!!

3 个答案:

答案 0 :(得分:1)

你应该阅读Vlad Mihalcea的这篇文章:

How to batch INSERT and UPDATE statements with Hibernate

答案 1 :(得分:1)

您需要确保已设置hibernate属性:

hibernate.jdbc.batch_size

因此Hibernate可以批量处理这些插入,否则它们将一次完成一次。

答案 2 :(得分:1)

无法一次性插入所有实体。即使你可以在内部执行类似session.save(emplList)的操作,Hibernate也会逐一保存。

因此,Hibernate用户指南StatelessSession不使用批处理功能:

  

StatelessSession接口定义的insert(),update()和delete()操作直接在数据库行上运行。它们导致相应的SQL操作立即执行。它们与Session接口定义的save(),saveOrUpdate()和delete()操作具有不同的语义。

而是使用普通会话并不时清除缓存。实际上,我建议您首先测量代码,然后进行更改,例如使用hibernate.jdbc.batch_size,这样您就可以看到任何调整都增加了您的负载。

尝试改变它:

session = sessionFactory.openSession();
int count = 0;
int step = 0;
int stepSize = 1_000;
long start = System.currentTimeMillis();
for(Employee e:emplList) {
    session.save(e);
    count++;
    if (step++ == stepSize) {
        long elapsed = System.currentTimeMillis() - start;
        long linesPerSecond = stepSize / elapsed * 1_000;
        StringBuilder msg = new StringBuilder();
        msg.append("Step time: ");
        msg.append(elapsed);
        msg.append(" ms Lines: ");
        msg.append(count);
        msg.append("/");
        msg.append(emplList.size());
        msg.append(" Lines/Seconds: ");
        msg.append(linesPerSecond);
        System.out.println(msg.toString());
        start = System.currentTimeMillis();
        step = 0;
        session.clear();
    }
}
transcation.commit;

关于hibernate.jdbc.batch_size - 您可以尝试不同的值,包括一些非常大的值,具体取决于使用的基础数据库和网络配置。例如,对于应用服务器和数据库服务器之间的1gbps网络,我使用10,000的值,每秒给我20,000条记录。

stepSize更改为hibernate.jdbc.batch_size的相同值。