Mybatis-plus 的批量插入真的不能用吗?
一、前言
在很多公司,经常听到“不要用 mybatis-plus 的批量插入,它其实也是遍历插入,性能很差的”。真的是这样吗?我们不应该人云亦云,应该自己去探究下。
我们先针对这个观点分析下,总结出来他们的看法大概率是下面的其中一种:
遍历插入,反复创建。这是一个比较重的操作,所以性能很差。
这里不用看源码也能知道,因为这个和 mybatis-plus 没关系,而且我们现在使用了 SpringBoot,一般也用它的 JDBC 启动依赖。连接和连接池不是本章节的重点,就不展开讲了,总的来说这观点是不正确的。
一条 insert 就一次网络 IO,数量多了,这是个很可观且没必要的开销,所以性能差。
二、走进源码
对这第二个观点,笔者结合源码给出自己的观点。给出笔者的一些相关配置(我使用 mybatis-plus 的版本是 3.5.3.1)。
pom.xml 如下:
application.yml 如下:
笔者的 Service 如下图:
1. 进入 saveBatch 看下
发现里面会给我们这个批量操作开启了事务(如果是期望插入一条就成功一条的,这批量方法就不适用了)并且是有限制提交数量的,默认 1000。
2. 往里 ServiceImpl#saveBatch 走
看到了 mybatis-plus 的批量插入是一条条插入的,但是这个一次次的遍历是真的发送给 MySQL 了吗?这里留一个疑问。我们只要记得这里有一个钩子,后面会回调回来执行
3 SqlHelper#executeBatch(Class<?>, Log, Collection, int, BiConsumer<SqlSession,E>)
sqlSession 是从哪里来的呢?我们去看下截图里面的 executeBatch。
4 SqlHelper#executeBatch(Class<?> entityClass, Log log, Consumer consumer)
结合前面的代码就知道了,我这里是到了 1000(默认配置 1000,并且我批量保存的 list 超过了 1000),就会开启会话,将内存的 sql 全部刷到 MySQL,然后回去继续遍历。
三、总结
到这里大家应该都清楚的知道了 mybatis-plus 的批量插入虽然是遍历插入,但是不是一个 insert 就一次 IO,而是打包了一次发送一批的,所以性能不会有什么太大问题。不过,笔者这里不是鼓吹大家都用这个批量插入就好了,实际工作中会有更多要求,有时这个简单的批量插入是没法满足的。因此,笔者只是提倡可以根据自己工作实际情况决定,但是性能方面就不用太过担心,mybatis-plus 也有考虑的。
四、扩展
如果使用 mybatis-plus 3.4+ 版本,并且连接的是 MySQL 8.0 或更高版本的数据库,那么 mybatis-plus 将会自动利用 MySQL 8.0 的原生批量插入功能来执行批量插入操作。
具体实现的关键是在 mybatis-plus 的底层使用了 mybatis-plus 的批量新增方法时,mybatis-plus 会将待插入的对象列表传递给底层。
需要注意的是,要确保以下条件满足才能利用
使用
使用兼容
使用 mybatis-plus 3.4+ 版本
版权声明: 本文为 InfoQ 作者【这我可不懂】的原创文章。
原文链接:【http://xie.infoq.cn/article/18857237b0c002f0ea71fd8b5】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论