一、背景
项目中经常会遇到需要对数据库进行大批量数据导入的问题,就目前java应用常用的springboot+mybatis-plus架构而言,在大批量数据导入时不是很清晰,本文做简单分析及解决,希望可以帮到各位
以一个实际项目需求为例:读取一个txt文本的内容,将其按行存入mysql,数据行数大约在十万到百万级别,现对不同的导入实现极其效果做简要说明
二、思路
mybatis-plus包含了两种预定的的crud接口
com.baomidou.mybatisplus.core.mapper.BaseMapper
com.baomidou.mybatisplus.extension.service.IService
BaseMapper只有单条的插入方法,但是可以自行扩展批量插入接口 IService提供了saveBatch方法
另外也可以通过原始的jdbc进行实现
三、结论
为节约时间,我们先看结果及结论
本次测试主要为对比各批次导入方式间的性能差距,导入时长包络部分文本读取等业务逻辑时间,但对测试目标无影响
总体而言,直接通过jdbc导入性能最好,符合我们越靠底层速度越快的常识,而使用mybatis-plus时,对baseMapper扩充的批量导入速度最快,与jdbc方式相比略慢,但是差距不大
建议:追求性能最优请选择jdbc方式进行实现,性能没有很高要求的可以扩展baseMapper进行实现,毕竟代码量和可维护性要高很多
四、jdbc实现
jdbc方式没什么好说的,拼接sql执行即可
如果使用预编译statement,需要注意url的批处理属性rewriteBatchedStatements=true打开,导入时间随批大小增加而缩短,增速逐渐放缓,具体批大小各位可根据自己的业务数据尝试,每批越大,网间通信的时间占比越少
五、baseMapper批处理实现
mybatis-plus用起来很方便,遗憾的是baseMapper中没有批处理方法,需要我们自己写一下,还是拼接sql的处理,具体如图
注解写着不太好看,但我实在不想写xml哈哈,毕竟用plus就是为了不写xml嘛,不习惯的同学也可以写在xml里
六、IService实现
首先需要定义接口
然后需要实现一下并且继承ServiceImpl以调用父类方法
这样我们就可以调用ServiceImpl的saveBatch方法啦,来看下这个方法
大致分析一下,应该是使用for循环逐条插入,这个就比较离谱,所以性能也差的离谱,不太明白为什么会有这样的实现
另外查阅资料有的文章说可以在url中配置批处理走批插入,我找了一会也没找到相应的代码,如果有同学了解的可以告诉我哈,贴个链接大家看看
批处理 rewriteBatchedStatements=true
七、结束
那么这里基本就是各框架对处理sql语句实现的批处理插入了,到这里一般的系统需求都是可以满足了,后续有机会的话再研究其他的优化方式