大批量数据插入数据库实践

一,背景介绍

  实际投产过程中,遇到过各种报表或者大数据分析的场景,总不可避免较大量级的数据落库需求。

二,实现方式

  1,事务分割提交

  即开启事务->插库->每隔一定数目提交一次

  2,mybatis的foreach标签

  本质上是将字符串拼接到insert语句的values中

三,say nothing without codes

  1,先介绍事务提交方式。上代码  

public int synCustomerByTrans(InputStream inputStreamFromSftp) throws Exception {
        //获取文件
        String temp = null;
        int row = 0;
        //开启事务
        SqlSession sqlSession = transManager.openSession();
        try (InputStreamReader isr = new InputStreamReader(inputStreamFromSftp, "GBK");
             BufferedReader reader = new BufferedReader(isr);) {
            ArrayList<Customerinformation> list = new ArrayList<>(2000);
            while ((temp = reader.readLine()) != null) {
                //解析数据
                Customerinformation ci = utilForFillName.convertToCustomer(temp);
                if (ci != null) {
                    row++;
                    cbcMapper.addCustomer(ci, sqlSession);
                }
                if (row % 2000 == 0) {
                    transManager.commit(sqlSession);
                }
            }
            return row;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(row + "");
        } finally {
            transManager.close(sqlSession);
        }
    }

 

  代码非常简单,即先开启事务,接着循环读文件,并将解析的对象插入数据库中,每隔2000条数据提交一次,最后关闭事务,为了代码简单,最后关闭事务的时候会尝试先提交,避免有多余的数据尚未提交

另外mapper里的代码非常简单,这里就不贴了。

  2,执行效果

  此次导入数据为6w,每隔对象86个属性字段。用时40来分钟,平均速度约250条/秒

  3,batch方式,上代码

  

public int synCustomerByBatch(InputStream inputStreamFromSftp) throws Exception {
        //获取文件
        String temp = null;
        int row = 0;
        try (InputStreamReader isr = new InputStreamReader(inputStreamFromSftp, "GBK");
             BufferedReader reader = new BufferedReader(isr);) {
            ArrayList<Customerinformation> list = new ArrayList<>(2000);
            while ((temp = reader.readLine()) != null) {
                Customerinformation ci = utilForFillName.convertToCustomer(temp);
                if (ci != null) {
                    row++;
                    list.add(ci);
                }
                if (row % 2000 == 0) {
                    cbcMapper.batchAddCustomer(list);
                    list.clear();
                }
            }
            cbcMapper.batchAddCustomer(list);
            return row;
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception(row + "");
        }
    }

    代码也很简单,解析处理的数据先存放在list中,(list指定容量也是减少resize耗时),然后利用mybatis的foreach插入list,代码比较简单也就补贴了。

  4,执行效果

  数据同上,6w条数据,每条数据86个字段,耗时50来秒,对的你没看错,50来秒,感觉被狠狠凿了一下

四,总结

  本来以为事务会很快,没想到批量更快,仔细分析下,事务开启,设置回滚点等等耗费资源比较大。values方式拼接就好,只是有点浪费空间。实验也证实了这点。

  事务方式占内存大约500M,而后者约占内存800M,使用的时候一定要注意。

posted @ 2020-07-01 22:20  superChong  阅读(915)  评论(0编辑  收藏  举报