大批量数据插入数据库实践
一,背景介绍
实际投产过程中,遇到过各种报表或者大数据分析的场景,总不可避免较大量级的数据落库需求。
二,实现方式
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,使用的时候一定要注意。