当您调用时
session.save(),hibernate将生成一个INSERT SQL。该INSERT
SQL将附加在刷新期间(即
session.flush())发布给DB 。
在刷新过程中,如果
hibernate.jdbc.batch_size将其设置为某个非零值,则Hibernate将使用JDBC2
API中引入的批处理功能向数据库发出批处理插入SQL。
例如,如果您有
save()100条记录,而您的记录
hibernate.jdbc.batch_size设置为50。在刷新期间,请不要发出以下SQL
100次:
insert into TableA (id , fields) values (1, 'val1');insert into TableA (id , fields) values (2, 'val2');insert into TableA (id , fields) values (3, 'val3');.........................insert into TableA (id , fields) values (100, 'val100');
Hiberate将它们分为50个批处理,并且仅向数据库发出2条SQL,如下所示:
insert into TableA (id , fields) values (1, 'val1') , (2, 'val2') ,(3, 'val3') ,(4, 'val4') ,......,(50, 'val50')insert into TableA (id , fields) values (51, 'val51') , (52, 'val52') ,(53, 'val53') ,(54, 'val54'),...... ,(100, 'val100')
请注意,如果插入表的主键为,则Hibernate将透明地禁用JDBC级别的插入批处理
GenerationType.Identity。
从您的日志中:您
save()只有一条记录,然后是
flush(),因此对于每次刷新,仅要处理一条附加的INSERT
SQL。这就是Hibernate无法帮助您批量插入的原因,因为只有一个INSERT
SQL要处理。
save()在调用之前,您应该最多保留一定数量的记录,
flush()而不是
flush()每次都调用
save()。
批处理插入的最佳实践是这样的:
Session session = sessionFactory.openSession();Transaction tx = session.beginTransaction();for ( int i=0; i<888888; i++ ) { TableA record = new TableA(); record.setXXXX(); session.save(record) if ( i % 50 == 0 ) { //50, same as the JDBC batch size //flush a batch of inserts and release memory: session.flush(); session.clear(); }}tx.commit();session.close();
您分批保存并刷新记录。在每个批处理的末尾,您应该清除持久性上下文以释放一些内存,以防止在将每个持久性对象放入第一级缓存(JVM的内存)中时导致内存耗尽。您也可以禁用二级缓存以减少不必要的开销。
参考:
- Hibernate官方文档:第14章。批处理
- 休眠批处理–为什么您可能不使用它。(即使您认为自己是)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)