`

Hibernate批处理操作优化 (批量插入、更新与删除)

 
阅读更多

转载:http://blog.sina.com.cn/s/blog_4550f3ca0101jhr9.html
问题描述

我开发的网站加了个新功能:需要在线上处理表数据的批量合并和更新,昨天下午发布上线,执行该功能后,服务器的load突然增高,变化曲线异常,SA教育了我一番,让我尽快处理,将CPU负载降低。

工作所需,我经常要写些程序批量处理数据,每次执行几十万数据处理的时候,我机子的CPU都会飙高,而且数据处理速度会越来越慢。比如第一个1W条要5分钟,第二个1W条就要10分钟,要干其他事情的时候机子也卡的不行,只能等着处理完数据。

其实我一直认为是数据量太大,从来不认为是程序问题,所以一直没怎么关注过。这次问题浮上表面,所以要好好解决下!

产生原因

主要原因:Hibernate的一级缓存影响。

我们每次保存的东西都会保存在Session缓存中,这就是Hibernate的一级缓存,如果我们一直循环执行save等操作,缓存里东西会越来越多,速度也就越来越慢,服务器一直在循环处理,自然也会增加负载。

这本来就是Hibernate不擅长的地方,而且一级缓存不可以不用,如果我们要保存的数据量十分巨大,那么在程序中执行添加、更新方法时,Session对象自身开辟的一级缓存会不断消耗,直至OutOfMemoryError (内存溢出异常)。

这就需要我们管理好Hibernate的缓存,或者不使用Hibernate。

解决方案

批量插入优化

1、仍旧用Hibernate API来进行批处理,但在一定的量的时候,及时的清除缓存。

1)优化Hibernate,在配置文件中设置hibernate.jdbc.batch_size参数,来指定每次提交SQL的数量。 配置hibernate.jdbc.batch_size参数的原因就是尽量少读数据库,hibernate.jdbc.batch_size参数值越大,读数据库的次数越少,速度越快。





   
        .........
         name="hibernate.jdbc.batch_size">50
        .........
   


2)程序及时清除缓存,即每插入一定量的数据后及时把它们从内部缓存中清除掉,释放占用的内存。 Session实现了异步write-behind,它允许Hibernate显式地写操作的批处理。

示例代码:


// 每处理50条清空缓存
session.save(myObject);
if (i/50 == 0) {
    session.flush();
    session.clear();
}

// 在我的项目中写法如下:
if (i/50 == 0) {
    this.getHibernateTemplate().flush();
    this.getHibernateTemplate().clear();
}

2、通过JDBC API来做批量插入,绕过Hibernate API。这个方法性能上是最好的,也是最快的。

示例代码:


String insertSql = "insert into user(name,address) values(?,?)";
Session session = getHibernateTemplate().getSessionFactory().openSession();
Connection conn = session.connection();
PrepareStatement stmt = conn.prepareStatement(insertSql);

// 方式1:自动提交
conn.setAutoCommit(true);
for(int i = 0; i++; i<</span>10000) {
    stmt.setString(1, "testName");
    stmt.setString(2, "testAddress");
    stmt.execute();
}

// 方式2:批量提交
conn.setAutoCommit(false);
for(int i = 0; i++; i<</span>10000) {
    stmt.setString(1, "testName");
    stmt.setString(2, "testAddress");
    stmt.addBatch();
    if (i % 100 == 0) {
        stmt.executeBatch();
        conn.commit();
    }
}
stmt.executeBatch();
conn.commit();

// 关闭session
session.close();

附测试数据:


// 测试方法:循环插入10000条数据,拆分10页,每页1000条。

// 直接Hibernate的save()方法,不做任何处理。
page 0 process time : 5925
page 1 process time : 6722
page 2 process time : 8019
page 3 process time : 9456
page 4 process time : 10263
page 5 process time : 11511
page 6 process time : 12988
page 7 process time : 13969
page 8 process time : 15196
page 9 process time : 16820

// Hibernate的save()方法,但每1个清除缓存。
page 0 process time : 10257
page 1 process time : 10709
page 2 process time : 11223
page 3 process time : 10595
page 4 process time : 10990
page 5 process time : 10222
page 6 process time : 10453
page 7 process time : 10196
page 8 process time : 9645
page 9 process time : 10295

// Hibernate的save()方法,但每50个清除缓存。
page 0 process time : 5848
page 1 process time : 5480
page 2 process time : 5739
page 3 process time : 5960
page 4 process time : 6287
page 5 process time : 5947
page 6 process time : 7012
page 7 process time : 6235
page 8 process time : 6063
page 9 process time : 6055

// JDBC的auto commit 方式
page 0 process time : 840
page 1 process time : 800
page 2 process time : 800
page 3 process time : 847
page 4 process time : 806
page 5 process time : 829
page 6 process time : 1042
page 7 process time : 893
page 8 process time : 857
page 9 process time : 854

// JDBC的batch方式,每50个commit
page 0 process time : 827
page 1 process time : 801
page 2 process time : 918
page 3 process time : 828
page 4 process time : 856
page 5 process time : 831
page 6 process time : 815
page 7 process time : 842
page 8 process time : 817
page 9 process time : 937

经测试:

1)若直接使用Hibernate,处理同样数据的时间会递增,甚至成倍增加,而且在测试过程中CPU使用率一直在70%上下。

2)若在使用Hibernate中每save一次都清空缓存的话,虽然时间不会递增,但处理速度很慢。在本例中采用每50个清空一次缓存较为合适,实际应用视情况而定。 一定量的时候清空缓存,虽然速度上没有提升,但会比较稳定,不会随着时间陡增,而且测试中CPU使用率也维持在20%上下,可以挽救一点性能损失,使系统相对稳定。

3)若使用JDBC API,不论auto commit方式还是batch方式,相比Hibernate在性能上都有近10倍的提升。不过在数据量较大的时候,推荐使用batch方式。

批量更新与删除优化

Hibernate2中,对于批量更新/删除操作,都是先将符合要求的数据查出来,然后再做更新/删除操作。这样一来会占用大量内存,而且海量数据处理的时候性能很低。

而Hibernate3对批量更新/删除提供了支持,能够直接执行批量更新或批量删除语句,无需把被更新或删除的对象先加载到内存中,类似于JDBC的批量更新/删除操作。

不过对于循环处理数据更新和删除场景,建议还是使用JDBC,方法同上:批量插入的方法2。

http://youngflying.com/2012/09/14/hibernate-batch-processing/
分享到:
评论

相关推荐

    Hibernate批量处理

    批量处理对于需要在短时间内处理大量数据的应用尤其重要,如批量更新、批量插入或批量删除等场景。 #### 二、批量处理的必要性 在实际开发过程中,当需要处理大量数据时,传统的逐条处理方式不仅占用大量的内存...

    Hibernate下数据批量处理解决方案

    对于更新和删除操作,可以使用`scroll()`方法,这在Hibernate 2.1.6或更高版本中是支持的。`scroll()`方法返回一个`ScrollableResults`对象,允许我们以游标方式处理结果集,这在处理大量数据时非常有效。同样,我们...

    Java中Hibernate的批量插入

    然而,在处理大量数据的批量操作时,如批量插入、更新或删除,如果不采取适当的策略,可能会导致性能问题甚至出现内存溢出异常。针对这种情况,Hibernate提供了一些批量处理的解决方案。 批量插入是处理大量数据...

    hibernate的查询方式介绍和hibernate的批处理和连接池配置hibernate

    批处理是 Hibernate 中一种提高性能的方法,特别是在进行大量数据的插入、更新或删除时尤为明显。 - **默认行为** - 默认情况下,Hibernate 每次执行一条 SQL 语句后都会自动提交事务。 - **批量处理** - 可以...

    Hibernate程序性能优化的考虑要点

    - Hibernate支持批处理操作,如批量插入、更新或删除。通过设置`batch_size`参数,可以控制一次批处理操作中的记录数量,减少数据库往返次数,提高批量操作的效率。 **3. 二级缓存使用:** - 合理配置并使用...

    hibernate代码优化基于配置的多表查询

    例如,使用`Session.flush()`和`Session.clear()`控制事务边界,或配置`hibernate.jdbc.batch_size`来批量插入、更新和删除数据。 7. **避免N+1查询问题**: 当遍历一个集合并访问其关联属性时,可能会触发多次...

    Hibernate批量处理数据

    批量更新操作与批量插入类似,也需要关注内存管理和性能优化。对于大量数据的更新操作,可以采用以下策略: 1. **使用ScrollableResults**:当需要返回多行数据时,可以使用`scroll()`方法,这种方式可以充分利用...

    hibernate数据库相关操作步骤

    - 使用批处理:批量处理多个保存、更新或删除操作,以减少数据库交互次数。 - 适当使用懒加载和立即加载:避免加载不必要的关联对象,减小内存开销。 - 优化HQL和SQL:避免全表扫描,利用索引,减少子查询。 ...

    hibernate3.5完整jar

    10. **批处理操作**:通过设置批处理大小,Hibernate可以优化批量插入、更新和删除的性能,减少与数据库的交互次数。 11. **JPA支持**:虽然Hibernate最初是一个独立的ORM框架,但在3.5版本中,它也兼容Java ...

    Hibernate性能优化共9页.pdf.zip

    2. **批处理**:批量操作可以减少数据库交互次数,比如批处理插入、更新和删除。通过设置`hibernate.jdbc.batch_size`,可以在一次JDBC连接中执行多条SQL语句。 3. **懒加载与立即加载**:理解实体关系的加载策略,...

    Hibernate

    本文将深入探讨在Hibernate框架下,如何有效地处理大规模数据的批量插入、更新和删除操作。 #### 批量数据插入 传统的Hibernate数据插入方式往往采用单次插入单个实体对象的方式,这在处理小规模数据时效率尚可,...

    Hibernate 中文参考文档

    为了提高性能,Hibernate提供了批量插入、更新和删除功能,以及延迟加载、批处理等优化策略。合理使用这些特性可以显著提升应用性能。 综上所述,Hibernate中文参考文档详尽地阐述了如何使用Hibernate进行数据持久...

    day36-hibernate检索和优化 02-Hibernate检索方式:简单查询及别名查询

    3. **批处理**:批量插入、更新或删除操作可以显著提高效率。 4. **预编译SQL**:使用HQL或Criteria的预编译功能,可以减少SQL解析的时间。 5. **结果集映射优化**:避免使用“select *”,只选择需要的字段,减少...

    Hibernate高级操作

    Hibernate支持批处理,比如批处理更新和插入,可以显著提高数据库操作的性能。通过设置`hibernate.jdbc.batch_size`配置,可以指定一次提交的SQL语句数量。 10. **事件监听器** Hibernate提供了一套事件监听机制...

    hibernate包详解+hibernatePPT

    2. **批处理**:批量插入、更新和删除数据,减少数据库交互次数。 3. **延迟加载(Lazy Loading)**:只在真正需要时加载关联对象,减少内存消耗。 **六、hibernatePPT** 提供的`hibernatePPT`可能是对Hibernate...

    浅析Hibernate下数据批量处理方法.doc

    标题"浅析Hibernate下数据批量处理方法"和描述中提到,早期的Hibernate在批量插入时可能存在效率问题,但最新版本已经进行了优化,例如通过设置`batch_size`参数来提高批量处理的性能。`batch_size`设置的是JDBC...

    Hibernate框架jia包

    - 批量操作:利用批处理更新或删除,减少数据库交互次数。 -延迟加载(Lazy Loading):只在需要时加载关联对象,避免数据冗余。 8. **HQL和Criteria API**: HQL是面向对象的查询语言,类似于SQL但更接近Java。...

    Hibernate管理Session和批量操作分析

    2. **通过HQL(Hibernate Query Language)**:利用HQL语句实现批量操作,比如更新或删除,可以避免加载整个对象到内存。 3. **通过StatelessSession**:StatelessSession不维护任何持久化状态,没有一级缓存,适合...

    hibernate中文参考文档

    4. 支持批处理:可以批量插入、更新或删除数据,提升效率。 5. 查询语言:HQL和 Criteria API,提供灵活的数据检索方式。 6. 支持级联操作:如级联保存、更新、删除,简化关联对象的管理。 四、配置与使用 1. 配置...

Global site tag (gtag.js) - Google Analytics