使用Hibernate批量插入或更新?

Jus*_*yul 21 java mysql hibernate

我需要从每日CSV文件中消耗大量数据.CSV包含大约120K条记录.使用hibernate时,这会慢慢爬行.基本上,当使用saveOrUpdate()时,似乎hibernate在每个INSERT(或UPDATE)之前都在执行SELECT; 对于使用saveOrUpdate()持久化的每个实例,在实际INSERT或UPDATE之前发出SELECT.我可以理解它为什么会这样做,但它对于进行批量处理非常低效,而且我正在寻找替代方案

我确信性能问题在于我使用hibernate的方式,因为我有另一个版本使用本机SQL(以相同的方式解析CSV)以及围绕这个新版本的字面运行圈子)

那么,对于实际问题,是否存在一个hibernate替代mysqls"INSERT ... ON DUPLICATE"语法?

或者,如果我选择为此执行本机SQL,我可以在hibernate事务中执行本机SQL吗?意思是,它会支持提交/回滚吗?

小智 34

批量操作存在许多可能的瓶颈.最好的方法在很大程度上取决于您的数据.请查看有关批处理的Hibernate手册部分.

至少要确保使用以下模式(从手册中复制):

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();
Run Code Online (Sandbox Code Playgroud)

如果要将平面文件映射到非常复杂的对象图形,则可能需要更具创造性,但基本原则是必须在每次刷新/提交时将大小合适的数据块推送到数据库之间找到平衡点并避免爆炸会话级缓存的大小.

最后,如果您不需要Hibernate来处理任何集合或级联以正确插入数据,请考虑使用StatelessSession.


Tom*_*son 5

根据对类似问题的回答,可以通过将Hibernate配置为使用使用数据库的upsert功能的自定义存储过程来插入对象来完成.但它并不漂亮.


sha*_*eef 5

来自Hibernate 批处理 对于更新,我使用了以下内容:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

ScrollableResults employeeCursor = session.createQuery("FROM EMPLOYEE")
                                   .scroll();
int count = 0;

while ( employeeCursor.next() ) {
   Employee employee = (Employee) employeeCursor.get(0);
   employee.updateEmployee();
   seession.update(employee); 
   if ( ++count % 50 == 0 ) {
      session.flush();
      session.clear();
   }
}
tx.commit();
session.close();
Run Code Online (Sandbox Code Playgroud)

但对于插入我会选择jcwayne答案