
01 引言
批量插入数据是我们业务中经常遇到的,我们习惯了手搓sql如:
insert into user_info (`name`, `age`, `created_time`) values
<foreach item ="item" collection="list" separator=",">
(#{item.name}, #{item.age}, #{item.createdTime})
</foreach>
这样的脚本,适用于数据量不大的情况,基本满足业务需求,但是却存在安全隐患。当传输的数据量过大时,可能会引起异常。
本节,我们将对比不同的写法以及响应的时间的消耗。
02 日常批量插入
insert into tb (col1, col2) values (val1, val2),......
上面的这种写法确实比一条条的数据入库的速度快太多,我们这里只横向对比不同的批量插入。我们先看看Mysql官方给的Insert执行的流程。

官网地址:https://dev.mysql.com/doc/refman/8.4/en/insert-optimization.html
2.1 安全隐患
所谓的安全隐患,其实就是Mysql的一些配置。而这些配置直接影响sql是否会执行以及执行的效率。
bulk_insert_buffer_size:max_allowed_packet
bulk_insert_buffer_size
Myisam引擎参数,在使用myisam引擎执行INSERT ... SELECT,INSERT ... VALUES (...), (...), ...,LOAD DATA INFILE批量插入时,会采用一种缓存树的内存结构来优化插入速度。默认8M。

max_allowed_packet
控制了 MySQL 服务器接收和发送的最大数据包的大小,默认64M。

因为小编测试的Mysql引擎使用的是innodb,所以暂时不考虑第一个参数。小编准备了10W条数据一次全部插入到数据库,就报错了:

所以呢,当一次插入的数据达到一定的数据就会出现异常。
2.2 分批插入
我们通过1W条数据测试一下,不同数据插入的结果:
@Test
public void test01() {
List<UserInfo> list = new ArrayList<>();
for (int i = 1; i <= 10000; i++) {
UserInfo userInfo = new UserInfo();
userInfo.setName("test" + i);
userInfo.setAge(new Random().nextInt(1,90));
userInfo.setCreatedTime(LocalDateTime.now());
list.add(userInfo);
}
List<List<UserInfo>> partition = Lists.partition(list, 5000);
StopWatch stopWatch = new StopWatch();
stopWatch.start();
for (List<UserInfo> userInfos : partition) {
userInfoMapper.insertBatch(userInfos);

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



