2016-06-24 59 views
3

我有3个表中插入/更新超过15000行的要求。所以这是总共45k插入。使用无状态会话批量插入/更新 - 休眠

在线上阅读后,我在休眠状态下使用了Statelesssession,因为它没有上下文缓存,所以它是批处理的最佳选择。

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

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

有没有办法一次保存所有实体对象? 保存整个集合,而不是一个一个地去做?

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

干杯!

+0

你有没有用简单的Session试过'hibernate.order_inserts'和'hibernate.order_updates'?你可以在保存一个员工时显示执行SQL语句吗? –

回答

1

你需要确保你已经设置休眠属性:

hibernate.jdbc.batch_size

让Hibernate可以批这些插入,否则他们将一次完成一个。

+0

我厌倦了这个正常的会话,它仍然需要相同的时间或关闭。 –

1

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

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

插入(),更新()和删除()由StatelessSession接口定义的操作直接在数据库中的行操作。它们导致相应的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

+0

所以基本上你说我不能减少这些插入的时间。有没有其他框架提供这样的东西? –

+0

不是的,因为它是基于jdbc的。 – DiogoSantana

+0

使用批量jdbc批量插入可以使其更快。只需使用正常的Hibernate Session并更改'hibernate.jdbc_batch_size'。 – DiogoSantana