问题描述

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

  2. 工作所需,我经常要写些程序批量处理数据,每次执行几十万数据处理的时候,我机子的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参数值越大,读数据库的次数越少,速度越快。

<!--设置hibernate.jdbc.batch_size参数-->
<hibernate-configuration>
<session-factory>
.........
<property name="hibernate.jdbc.batch_size">50</property>
.........
<session-factory>
<hibernate-configuration>

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<10000) {
stmt.setString(1, "testName");
stmt.setString(2, "testAddress");
stmt.execute();
} // 方式2:批量提交
conn.setAutoCommit(false);
for(int i = 0; i++; i<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://www.verydemo.com/demo_c146_i31256.html)

Hibernate批处理操作优化 (批量插入、更新与删除)的更多相关文章

  1. .net使用SqlBulkCopy类操作DataTable批量插入数据库数据,然后分页查询坑

    在使用SqlBulkCopy类操作DataTable批量插入数据,这种操作插入数据的效率很高,就会导致每一条数据在保存的时间基本一样,在我们分页查询添加的数据是,使用数据的添加时间来排序就会出现每页的 ...

  2. SQL.Cookbook 读书笔记4 插入更新和删除

    第四章 插入更新和删除 4.1 插入数据 ,'PROGRA','NEW YOURK'); 4.2 从一个表向另一个表中复制 insert into dept_east(deptno,dname,loc ...

  3. Java批量插入更新操作

    以前总是说批量插入和更新的效率比非批量的要高,但是一直没有使用过批量处理数据的功能,现在由于项目中需要处理的数据量比较大,所以使用了批量处理的功能,java代码如下: 1.java实现批量插入数据: ...

  4. mapper mysl实现批量插入 更新

    1.批量插入 <insert id="insertConfirm" parameterType="java.util.List"> insert i ...

  5. MyBatis操作Oracle批量插入 ORA-00933: SQL 命令未正确结束

    最近在使用MyBatis操作Oracle数据库的时候,进行批量插入数据,思路是封装一个List集合通过Myabtis 的foreach标签进行循环插入,可是搬照Mysql的批量插入会产生 异常 ### ...

  6. Mysql优化批量插入数据

    最近为了测试项目,需要在Mysql中插入百万级测试数据,于是用到了批量插入,自己写了个简单的Spring Cloud项目. 开始时执行效率很慢,大概100条/秒,批次的大小也试过1000,2000,5 ...

  7. mysql批量插入更新操作

    //添加关联赠品(确定) public function addGiveGoods($ids,$child,$parent_sku_no){ $license=new LicenseModel(); ...

  8. Mysql数据库实践操作之————批量插入数据(100万级别的数据)

    第一种方法:使用insert into 插入 从Redis每次获取100条数据,根据条件去插入到Mysql数据库中: 条件: 如果当前队列中的值大于1000条,则会自动的条用该方法,该方法每次获取从队 ...

  9. Set,Sorted Set相关命令操作,批量插入及管道,事务

    Set SADD key member [member ...] 向key指定的set集合添加成员,次集合是排重的,从2.4版本后才支持添加多个如果key不存在则创建key以及set集合返回当前操作成 ...

随机推荐

  1. python如何获取某模块的版本信息

    1)module.__version__ 2)用dir(module)查看有没有版本信息 3)help(module)

  2. git无法clone远程代码库及git代理设置

    git作为一个版本管理神器,日常工作中自然也就少不了了:特别是Android开发,github和google是逃不过的了.然而很多时候需要用到git克隆远程的代码库,众所周知的原因google.and ...

  3. Android 模拟器genymotion安装,eclipse 插件

    genymotion是一款号称速度最快性能最好的android模拟器,它基于Oracle VM VirtualBox.支持GPS.重力感应.光.温度等诸多传感器:支持OpenGL 3D加速:电池电量模 ...

  4. Java for LeetCode 026 Remove Duplicates from Sorted Array

    Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...

  5. DP:Wooden Sticks(POJ 1065)

    摆木棍 题目大意:即使有一堆木棍,给一个特殊机器加工,木棍都有两个属性,一个是l一个是w,当机器启动的时候(加工第一根木棒的时候),需要一分钟,在这以后,设机器加工的上一根木棒的长度是l,质量是w,下 ...

  6. Java问题排查工具箱[转载]

    转载自:http://hellojava.info/?p=517 作者:阿里毕玄 问题排查除了最重要的解决思路和逻辑推导能力外,工具也是不可缺少的一部分,一个好用的工具可以事半功倍,甚至在某些情况下会 ...

  7. sublime 3103liense

    Sublime Text 3.x (after Build 309X) —– BEGIN LICENSE —–Michael BarnesSingle User LicenseEA7E-8213858 ...

  8. php 条件查询和多条件查询

    条件循环 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  9. 今天装了一个RTI工具

    就是一个协议,需要在本机运行,今天天气有变,还要陈到家里来安装光纤宽带,昨天晚上家里下了一场雷电交加的大雨,电停了一会

  10. 【Ubuntu日常技巧】【解决】Ubuntu 16 右上角的音量调节通知框不停地闪烁问题

    一. 先上干货 解决问题 1.1 安装工具alsa-tools-gui sudo apt-get install alsa-tools-gui 1.2 通过hdajackretask设置 直接执行命令 ...