惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
P
Privacy International News Feed
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
A
About on SuperTechFans
量子位
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
Recent Announcements
Recent Announcements
博客园 - 叶小钗
B
Blog RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
C
Check Point Blog
N
Netflix TechBlog - Medium
Y
Y Combinator Blog
P
Proofpoint News Feed
T
The Blog of Author Tim Ferriss
D
DataBreaches.Net
月光博客
月光博客
Engineering at Meta
Engineering at Meta
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
小众软件
小众软件
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
爱范儿
爱范儿
M
MIT News - Artificial intelligence
G
Google Developers Blog
MyScale Blog
MyScale Blog
Google DeepMind News
Google DeepMind News
D
Docker
有赞技术团队
有赞技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
Visual Studio Blog
Recorded Future
Recorded Future
I
InfoQ
T
Tailwind CSS Blog
MongoDB | Blog
MongoDB | Blog
人人都是产品经理
人人都是产品经理
云风的 BLOG
云风的 BLOG
美团技术团队
Vercel News
Vercel News
GbyAI
GbyAI
aimingoo的专栏
aimingoo的专栏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学

博客园 - 倾听-静轩水月

Mysql优化笔记 Arthas使用 vue2.0和vue3.0同时使用 零基础尝试mybatis-plus读写分离 零基础尝试搭建docker和nacos环境 零基础尝试mysql主从复制 找回windows应用商店 linux 开放端口 小白零基础在 Centos 7 中安装 mysql http转向https 内存不够导致编译报错:Information:java: java.lang.OutOfMemoryError: GC overhead limit exceeded docker常用命令 CentOS7使用命令行安装Oracle11GR2 使用Xshell连接VMware上的Linux虚拟机 mysql免安装版初次使用 微信小程序支付证书及SSL证书使用 SqlServer无备份下误删数据恢复 javaweb学习--javabean javaweb学习--jsp
mybatis-plus 批量插入示例
倾听-静轩水月 · 2023-07-30 · via 博客园 - 倾听-静轩水月

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