一、背景

项目中经常会遇到需要对数据库进行大批量数据导入的问题,就目前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进行实现

三、结论

为节约时间,我们先看结果及结论

本次测试主要为对比各批次导入方式间的性能差距,导入时长包络部分文本读取等业务逻辑时间,但对测试目标无影响

mybatics 批量插入数据到mysql mybatisplus批量导入_mybatis


总体而言,直接通过jdbc导入性能最好,符合我们越靠底层速度越快的常识,而使用mybatis-plus时,对baseMapper扩充的批量导入速度最快,与jdbc方式相比略慢,但是差距不大

建议:追求性能最优请选择jdbc方式进行实现,性能没有很高要求的可以扩展baseMapper进行实现,毕竟代码量和可维护性要高很多

四、jdbc实现

mybatics 批量插入数据到mysql mybatisplus批量导入_spring boot_02


jdbc方式没什么好说的,拼接sql执行即可

如果使用预编译statement,需要注意url的批处理属性rewriteBatchedStatements=true打开,导入时间随批大小增加而缩短,增速逐渐放缓,具体批大小各位可根据自己的业务数据尝试,每批越大,网间通信的时间占比越少

五、baseMapper批处理实现

mybatis-plus用起来很方便,遗憾的是baseMapper中没有批处理方法,需要我们自己写一下,还是拼接sql的处理,具体如图

mybatics 批量插入数据到mysql mybatisplus批量导入_java_03


注解写着不太好看,但我实在不想写xml哈哈,毕竟用plus就是为了不写xml嘛,不习惯的同学也可以写在xml里

六、IService实现

首先需要定义接口

mybatics 批量插入数据到mysql mybatisplus批量导入_mysql_04


然后需要实现一下并且继承ServiceImpl以调用父类方法

mybatics 批量插入数据到mysql mybatisplus批量导入_spring boot_05


这样我们就可以调用ServiceImpl的saveBatch方法啦,来看下这个方法

mybatics 批量插入数据到mysql mybatisplus批量导入_bc_06


大致分析一下,应该是使用for循环逐条插入,这个就比较离谱,所以性能也差的离谱,不太明白为什么会有这样的实现

另外查阅资料有的文章说可以在url中配置批处理走批插入,我找了一会也没找到相应的代码,如果有同学了解的可以告诉我哈,贴个链接大家看看

批处理 rewriteBatchedStatements=true

七、结束

那么这里基本就是各框架对处理sql语句实现的批处理插入了,到这里一般的系统需求都是可以满足了,后续有机会的话再研究其他的优化方式