🍀 前言
博客地址:
- CSDN:https://blog.csdn.net/powerbiubiu
👋 简介
本章节介绍如何通过Mybatis-Plus进行实现批量新增。
📖 正文
1 为何要批量插入?
前面章节已经介绍,Mapper接口只有一个insert
单挑插入的方法,而Service接口中批量插入saveBatch
的方法,也只能做到伪批量插入,实际还是利用了循环一条一条插入,这样会导致效率低,耗时长。
实际执行的SQL为
INSERT INTO tb_role ( role_name, role_code ) VALUES ( '超级管理员', 'ADMIN' )
INSERT INTO tb_role ( role_name, role_code ) VALUES ( '测试角色1号', 'TEST01' )
INSERT INTO tb_role ( role_name, role_code ) VALUES ( '测试角色2号', 'TEST02' )
INSERT INTO tb_role ( role_name, role_code ) VALUES ( '测试角色3号', 'TEST03' )
那么,我们该如何保证SQL的执行像下面这样执行呢,接下来我们开始进行操作
INSERT INTO
tb_role ( role_name, role_code )
VALUES
( '超级管理员', 'ADMIN' ),
( '测试角色1号', 'TEST01' ),
( '测试角色2号', 'TEST02' ),
( '测试角色3号', 'TEST03' );
2 实现批量插入
这里我们将通过Mybatis-Plus框架的SQL注入器实现一个真的批量插入功能。
2.1 创建SQL注入器
在项目config
目录下新增一个InsertBatchInjector
类,然后继承DefaultSqlInjector
类后,重新实现getMethodList
方法。
package com.power.mpdemo.config;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import java.util.List;
/**
* @author power
* @time 2023/12/23 07:50:28
* @Description
*/
public class InsertBatchInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
// super.getMethodList() 保留 Mybatis-Plus 自带的方法
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
// 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn
methodList.add(new InsertBatchSomeColumn());
return methodList;
}
}
在配置类中,添加了Mybatis-Plus内部提供的默认批量插入的InsertBatchSomeColumn
类,根据作者在源码中的描述,只在Mysql数据库中测试过,所以没有将该方法提供外部使用,所以当前我们这里批量插入只针对Mysql数据库。
2.2 配置SQL注入器
在前面章节,我们在config
包下创建的MybatisPlusConfig
类中,添加以下代码
/**
* 自定义批量插入 SQL 注入器
*
* @return
*/
@Bean
public InsertBatchInjector insertBatchSqlInjector() {
return new InsertBatchInjector();
}
2.3 配置BaseMapper
在config
包下,新增一个NewBaseMapper
的接口,继承Mybatis-Plus的BaseMapper
接口。
package com.power.mpdemo.config;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author power
* @time 2023/12/23 08:04:55
* @Description
*/
public interface NewBaseMapper<T> extends BaseMapper<T> {
// 批量插入
int insertBatchSomeColumn(@Param("list") List<T> batchList);
}
修改我们的RoleMapper
继承的接口为刚才创建的新接口
package com.power.mpdemo.mapper;
import com.power.mpdemo.config.NewBaseMapper;
import com.power.mpdemo.entity.Role;
/**
* <p>
* 角色表 Mapper 接口
* </p>
*
* @author power
* @since 2023-12-21
*/
public interface RoleMapper extends NewBaseMapper<Role> {
}
2.4 测试执行
@Test
public void insertBatch() {
List<Role> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(Role.builder()
.roleName("批量添加" + i)
.roleCode("batch" + i)
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.isDeleted(0)
.build()
);
}
int i = roleMapper.insertBatchSomeColumn(list);
System.out.println("添加结果:" + i);
}
// 添加结果:5
实际执行的SQL
INSERT INTO
tb_role (role_name,role_code,description,create_time,update_time,is_deleted)
VALUES
('批量添加0','batch0',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) ,
('批量添加1','batch1',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) ,
('批量添加2','batch2',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) ,
('批量添加3','batch3',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) ,
('批量添加4','batch4',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0)
3 性能对比
3.1 for循环插入
@Test
public void insertBatch() {
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
Role role = Role.builder()
.roleName("for循环" + i)
.roleCode("insert" + i)
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.isDeleted(0)
.build();
roleMapper.insert(role);
}
System.out.printf("总耗时:%s ms%n", System.currentTimeMillis() - start);
}
// 总耗时:11460 ms
3.2 Service接口批量插入
@Test
public void insertBatch() {
long start = System.currentTimeMillis();
List<Role> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
list.add(Role.builder()
.roleName("Service伪批量插入" + i)
.roleCode("saveBatch" + i)
.build()
);
}
roleService.saveBatch(list);
System.out.printf("总耗时:%s ms%n", System.currentTimeMillis() - start);
}
// 总耗时:1743 ms
3.3 真实批量插入
@Test
public void insertBatch() {
long start = System.currentTimeMillis();
List<Role> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(Role.builder()
.roleName("批量添加" + i)
.roleCode("batch" + i)
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.isDeleted(0)
.build()
);
}
roleMapper.insertBatchSomeColumn(list);
System.out.printf("总耗时:%s ms%n", System.currentTimeMillis() - start);
}
// 总耗时:252 ms
Tips:
根据执行结果发现,在插入数量同为10000条数据的情况下,for循环耗时最多,我们自己实现的真实批量插入耗时最少。尽管实际应用中我们不会使用for的方式批量插入,但是同样通过Mybatis-Plus框架实现的批量插入,Service
接口的saveBatch
方法的批量插入的耗时是自定义实现批量插入耗时的的6-7倍,当数据量十万百万级别的,就能体现出真实批量插入的性能的重要性了