2011-09-08 115 views
15

我需要从每日CSV文件中消耗相当多的数据。 CSV包含大约120K条记录。使用休眠时,这会减慢抓取速度。基本上,看起来在使用saveOrUpdate()时,hibernate在每一个INSERT(或UPDATE)之前都会执行SELECT操作。对于每个使用saveOrUpdate()持久化的实例,都会在实际的INSERT或UPDATE之前发出SELECT。我可以理解为什么它这样做,但它做非常低效的批量处理,我正在寻找替代品批量插入或更新与休眠?

我相信性能问题在于我使用hibernate的方式,因为我得到了另一个版本与原生SQL工作(解析CSV的激动人心的相同方式)和它的字面上围绕这个新版本的字面上运行的圆)

所以,到实际的问题,做一个休眠替代mysqls“INSERT ... ON DUPLICATE“语法存在吗?或者,如果我选择为此执行原生SQL,我可以在hibernate事务中执行原生SQL吗?意思是说,它会支持提交/回滚吗?

+0

你是什么意思“Hibernate是每一个插入(或更新)之前执行SELECT使用saveOrUpdate时,()。” ?你可以发布你用来保存数据的代码吗?顺便说一下,12万条记录是一个巨大的数据! – Rakesh

+0

刚刚发现一篇关于[休眠时批处理]的文章(http://onetouchcode.com/2016/08/21/batch-processing-example-in-hibernate/) – Shailendra

回答

22

批量操作有很多可能的瓶颈。最好的方法在很大程度上取决于你的数据是什么样子。查看关于批处理的Hibernate Manual部分。

在最低限度,确保您使用的是以下模式(从手动复制):

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处理任何集合或级联数据以便正确插入,请考虑使用StatelessSession

+0

我正在冲洗一个清理会话,我没有内存问题与代码。我有额外的选择问题! :P我通读手册,我找不到任何东西。数据非常简单,不需要级联。我只是需要摆脱这个任务,被称为120K次的冗余选择:P – JustDanyul

+0

@JustDanyul这个操作中新实体的近似百分比是多少(即实际上不需要多少百分比的选择)?你在使用版本控制吗? – jcwayne

+0

实际百分比会每天都在变化。但是,没有一项选择确实是必要的。现在大多数数据库(甚至像SQLite这样的“玩具”数据库)提供的功能可以让你在数据已经存在的情况下自动更新记录。 (不必先轮询它,找出它是否存在:)) – JustDanyul

0

“额外”选择是为您的数据生成唯一标识符。

切换到HiLo序列生成,您可以通过分配大小减少到数据库的序列往返。请注意,会出现在主键的空隙,除非你对希洛发电机调整序列值

1

如果使用序列或天然生成Hibernate将使用选择来获取ID:

<id name="id" column="ID"> 
    <generator class="native" /> 
</id> 

你应该使用希洛或seqHiLo发生器:

<id name="id" type="long" column="id"> 
    <generator class="seqhilo"> 
     <param name="sequence">SEQ_NAME</param> 
     <param name="max_lo">100</param> 
    </generator> 
</id> 
3

Hibernate Batch Processing 对于更新我用下面的:

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答案