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、此处为示例,实际业务中循环不要放在事务里面

 

热门相关:倾心之恋:总裁的妻子   上神来了   金粉   修真界败类   戏精老公今天作死没