mybatis-plus 批量插入示例
正常我们使用mybatis-plus插入的时候,首先想到的是 saveBatch 方法,不过看了下打印出来的sql和底层代码,才发现它并不是真正的批量插入。
IService 中的代码为
default boolean saveBatch(Collection<T> entityList) { return this.saveBatch(entityList, 1000); }
实现层 ServiceImpl 中的代码为
public boolean saveBatch(Collection<T> entityList, int batchSize) { String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE); return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> { sqlSession.insert(sqlStatement, entity); }); }
SqlMethod.INSERT_ONE 的中文枚举为
INSERT_ONE("insert", "插入一条数据(选择字段插入)", "<script>\nINSERT INTO %s %s VALUES %s\n</script>"),
通过监控控制台发现,它只是循环每1000条去插入,效率非常低。
参考网友的文章,找到一个支持批量操作的方法,下面直接贴上代码
1、添加批量操作参数类 CustomSqlInjector
/** * 支持自定义SQL注入方法 */ public class CustomSqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { // 获取父类SQL注入方法列表 List<AbstractMethod> methodList = super.getMethodList(mapperClass); // 将批量插入方法添加进去 methodList.add(new InsertBatchSomeColumn()); return methodList; } }
2、在MybatisPlusConfig中配置
@Bean public CustomSqlInjector customSqlInjector() { return new CustomSqlInjector(); }
3、添加自定义 Mapper接口
/** * 自定义Mapper,添加批量插入接口 * @param <T> */ @Mapper public interface CustomMapper<T> extends BaseMapper<T> { /** * 批量插入 * @param entityList 实体列表 * @return 影响行数 */ Integer insertBatchSomeColumn(Collection<T> entityList); }
4、将原来的Mapper业务接口,换成继承此接口
@Mapper public interface StudentDao extends CustomMapper<Student> { List<Student> query(Student student); }
5、再进行测试一下
@Transactional //事务注解要加上 @Override public void testBatchCreate() { List<Student> list = new ArrayList<>(); int startIndex = this.lambdaQuery().select(Student::getId).count(); for (int i = 1; i <= 1000000; i++) { Student student = new Student(); Long id = SnowFlake.nextId(); student.setId(id); student.setCode("studentCode-" + (startIndex + i)); student.setName("studentName-" + (startIndex + i)); list.add(student); } Long startTime = System.currentTimeMillis(); System.out.println("开始批量操作:" + startTime); int count = this.baseMapper.insertBatchSomeColumn(list); Long endTime = System.currentTimeMillis(); System.out.println("完成批量操作:" + endTime); System.out.println("用时:" + (endTime - startTime)); System.out.println("保存成功:" + count); //this.saveBatch(list); }
测试结果为,1000000条数据,用时大概在 35秒左右
注意事项:
1、mysql会提示超过 max_allowed_packet 设置的最大值,到 my.cnf文件(windows为my.ini)修改就行了,我这直接改成 200M
2、此处为示例,实际业务中循环不要放在事务里面
热门相关:倾心之恋:总裁的妻子 上神来了 金粉 修真界败类 戏精老公今天作死没