关于批量导入数据以及调优的一些总结

  刚完成的一个项目里有一个导入的功能,用户通过Excel表的形式,将数据存到数据库中。之前也没考虑过很多数据的情况,所以未对导入这块做任何优化。测试之后暴露出2个bug。

  Bug1、导入文件大于2M后直接报错。  这个问题是struts引起的,在struts的配置中有一个配置属性struts.multipart.maxSize,它默认是2000000字节,我们只需将这个值重新赋值为一个更大的值即可,此设为10M

<constant name="struts.multipart.maxSize" value="10000000" />

  Bug2、导入速度很慢,而且机器很卡。

  这个问题是hibernate引起的,这需要提下hibernate的缓存机制,其中包括一级缓存和二级缓存。机器越来越卡的罪魁祸首就是一级缓存,一级缓存会将每个你生成的数据对象保存到内存里。结果就是最后会造成内存溢出。按照这个思路我们就需要定期清理缓存。session.flush();session.clear();慢是因为上传过程中每一个数据对象都重新连接数据库一次所以很慢,所以我们可以选择hibernate的批量上传来解决这个问题。在hibernate的配置文件中也可以在spring的配置文件中直接加上:

<prop key="hibernate.jdbc.batch_size">20</prop><!--size可以视情况而定-->
<prop key="hibernate.cache.use_second_level_cache">false</prop><!--关闭二级缓存-->

然后java代码中:if(i % 20 ==0){

          ......

          session.flush();

          session.clear();

        }

  另一种思路就是不用hibernate直接用JDBC插入数据,这样就不存在内存溢出的问题了,而且通过jdbc方法导入的效率远高于hibernate策略。所以这也是我的最终解决方案。

同时,根据前人测试得出是用jdbc方案没必要在使用batch,使用batch速度反而会慢。

     Session session = getHibernateTemplate().getSessionFactory().openSession();
        Transaction tx=session.beginTransaction(); //使用Hibernate事务处理
        Connection conn=session.connection();
        conn.setAutoCommit(false);
        PreparedStatement stmt=conn.prepareStatement("insert into voucher_order(bankNo,bankName,voucherName,voucherNo,voucherCount,totalPrice)                     values(?,?,?,?,?,?)");
        for(int i=2;i<=sheetData.getLastRowNum();i++){
            setVoucherOrder(stmt,sheetData.getRow(i),noNameMap,voucherMap);
        }
        tx.commit();

 

参考文档:

http://home.51.com/wangliu007/diary/item/10053146.html

http://superjavason.iteye.com/blog/255423

http://blog.chinaunix.net/uid-25434387-id-1760827.html

  

  

posted on 2014-03-10 19:20  李江瑞  阅读(1230)  评论(0编辑  收藏  举报

导航