批量插入或使用休眠进行更新?

2022-09-01 11:40:26

我需要从每日CSV文件中消耗相当大量的数据。CSV 包含大约 120K 条记录。使用休眠时,这会减慢到爬网速度。基本上,在使用 saveOrUpdate() 时,休眠似乎在每次 INSERT (或 UPDATE) 之前执行 SELECT;对于使用 saveOrUpdate() 持久保存的每个实例,在实际的 INSERT 或 UPDATE 之前发出 SELECT。我可以理解它为什么要这样做,但是对于批量处理来说效率非常低下,我正在寻找替代方案。

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

因此,对于实际问题,mysqls的休眠替代方案“INSERT ...ON DUPLICATE“语法是否存在?

或者,如果我选择为此执行本机 SQL,是否可以在休眠事务中执行本机 SQL?这意味着,它将支持提交/回滚吗?


答案 1

批量操作中存在许多可能的瓶颈。最佳方法在很大程度上取决于数据的外观。查看有关批处理的休眠手册部分。

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

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();

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

最后,如果您不需要 Hibernate 来处理任何集合或级联来正确插入数据,请考虑使用无状态会话


答案 2

休眠批处理对于更新,我使用了以下内容:

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();

但是对于插入,我会去jcwayne答案


推荐