SpringBoot整合mybatisPlus实现批量插入并获取ID详解

本文主要是介绍SpringBoot整合mybatisPlus实现批量插入并获取ID详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《SpringBoot整合mybatisPlus实现批量插入并获取ID详解》这篇文章主要为大家详细介绍了SpringBoot如何整合mybatisPlus实现批量插入并获取ID,文中的示例代码讲解详细...

背景:需要实现批量插入并且得到插入后的ID。

使用for循环进行insert这里就不说了,在海量数据下其性能是最慢的。数据量小的情况下,没什么区别。

【1】saveBatch(一万条数据总耗时:2478ms)

mybatisplus扩展包提供的:com.baomidou.mybatisplus.extension.service.IService#saveBatch(Java.util.Collection<T>)

测试代码:

@Test
 public void testBatch1(){
     List<SysFile> list=new ArrayList<>();
     list.add(new SysFile().setFileName("fiel1"));
     list.add(new SysFile().setFileName("fiel2"));
     list.add(new SysFile().setFileName("fiel3"));
     list.add(new SysFile().setFileName("fiel4"));
     list.add(new SysFile().setFileName("fiel5"));
     list.add(new SysFile().setFileName("fiel6"));
     fileService.saveBatch(list);
     System.out.println(list);
 }

我们分析其实现原理如下:com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#saveBatch

@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveBatch(Collection<T> entityList, int batchSize) {
    String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE)China编程;
    int size = entityList.size();
    executeBatch(sqlSession -> {
        int i = 1;
        for (T entity : entityList) {
            sqlSession.insert(sqlStatement, entity);
            if ((i % batchSize == 0) || i == size) {
                sqlSession.flushStatements();
            }
            i++;
        }
    });
    return true;
}

其实也就是一条条插入。

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

【2】集合方式foreach(一万条数据总耗时:474ms)

SysFileMapper 自定义方法batchSaveFiles

public interface SysFileMapper extends BaseMapper<SysFile> {
    int batchSaveFiles(List<SysFile> entityList);
}

XML实现

<insert id="batchSaveFiles">
    insert  into tb_sys_file (file_name) values
    <foreach collection="list" item="item" separator=",">
        (#{item.fileName})
    </foreach>
</insert>

测试代码:

@Test
public void testBatch2(){
    List<SysFile> list=new ArrayList<>();
    list.add(new SysFile().setFileName("fiel1"));
    list.add(new SysFile().setFileName("fiel2"));
    list.add(new SysFile().setFileName("fiel3"));
    list.add(new SysFile().setFileName("fiel4"));
    list.add(new SysFile().setFileName("fiel5"));
    list.add(new SysFile().setFileName("fiel6"));
    fileMapperandroid.batchSaveFiles(list);
    System.out.println(list);
}

测试结果:

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

注意:这种方式得不到ID哦!

【3】MyBatis-Plus提供的InsertBatchSomeColumn方法(一万条数据总耗时:690ms)

这里mybatisplus版本是3.3.0。

编写mysqlInjector

public class MySqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
      js  //更新时自动填充的字段,不用插入值
        methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
        return methodList;
    }
}

为什么这里不用下面第二行的方式呢?

methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
methodList.add(new InsertBatchSomeColumn());

这两行代码分别添加了两个 InsertBatchSomeColumn 方法到 methodList 中。

第一个 InsertBatchSomeColumn 方法使用了一个 Lambda 表达式作为参数,该表达式用于过滤字段,只保留那些 getFieldFill 属性不是 FieldFill.UPDATE 的字段。

第二个 InsertBatchSomeColumn 方法没有参数,表示不进行任何过滤,直接插入所有字段。

注入到配置类

@EnableTransactionManagement
@MapperScan({"com.enodeb.mapper"})
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MySqlInjector sqlInjector() {
        return new MySqlInjector();
    }
}    

SysFileMapper 自定义方法

public interface SysFileMapper extends BaseMapper<SysFile> {

    int insertBatchSomeColChina编程umn(List<SysFile> entityList);

测试代码:

@Test
public void testBatch3(){
    List<SysFile> list=new ArrayList<>();
    list.add(new SysFile().setFileName("fiel1"));
    list.add(new SysFile().setFileName("fiel2"));
    list.add(new SysFile().setFileName("fiel3"));
    list.add(new SysFile().setFileName("fiel4"));
    list.add(new SysFile().setFileName("fiel5"));
    list.add(new SysFile().setFileName("fiel6"));
    fileMapper.insertBatchSomeColumn(list);
    System.out.println(list);
}

测试结果

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

这里不仅实现了【2】的效果,还可以得到插入后的ID。

【4】假设一万条/十万条数据的情况下,执行时间是多少

策略一万条十万条
方式一2478ms20745ms
方式二474ms2904ms
方式三690ms8339ms

① 方式一

@Test
    public void testBatch1(){
        long start=System.currentTimeMillis();
        List<SysFile> list=new ArrayList<>();
        SysFile sysFile;
        for(int i=0;i<10000;i++){
            sysFile=new SysFile();
            sysFile.setFileName("file"+i);
            list.add(sysFile);
        }
        fileService.saveBatch(list);
        long end=System.currentTimeMillis();
        System.out.println("一万条数据总耗时:"+(end-start)+"ms");
    }

一万条数据总耗时:2478ms

十万条数据总耗时:20745ms

② 方式二

@Test
public void testBatch2(){
     long start=System.currentTimeMillis();
     List<SysFile> list=new ArrayList<>();
     SysFile sysFile;
     for(int i=0;i<10000;i++){
         sysFile=new SysFile();
         sysFile.setFileName("file"+i);
         list.add(sysFile);
     }
     fileMapper.batchSaveFiles(list);
     long end=System.currentTimeMillis();
     System.out.println("一万条数据总耗时:"+(end-start)+"ms");
 }

一万条数据总耗时:474ms

十万条数据总耗时:2904ms

③ 方式三

@Test
public void testBatch3(){
    long start=System.currentTimeMillis();
    List<SysFile> list=new ArrayList<>();
    SysFile sysFile;
    for(int i=0;i<10000;i++){
        sysFile=new SysFile();
        sysFile.setFileName("file"+i);
        list.add(sysFile);
    }
    fileMapper.insertBatchSomeColumn(list);
    long end=System.currentTimeMillis();
    System.out.println("一万条数据总耗时:"+(end-start)+"ms");
}

一万条数据总耗时:690ms

十万条数据总耗时:8339ms

【5】百万条数据的情况下进行优化

方式二、方式三都是拼接为一条SQL,也就说有多少直接全部一次性插入,这就可能会导致最后的 sql 拼接语句特别长,超出了mysql 的限制。

这是什么意思呢?以MySQL为例,我们是需要考虑 max_allowed_packet 这个属性配置大小。其决定了你最大可以单次发送包的大小,这里可以修改为64M也就是 67108864。

但是这个不是最优解,最优解应该是控制每次插入的数量,比如一万条插入一次。

    @Test
    public void testBatch4(){
        List<SysFile> list=new ArrayList<>();
        SysFile sysFile;
        for(int i=0;i<100000;i++){
            sysFile=new SysFile();
            sysFile.setFileName("file"+i);
            list.add(sysFile);
        }
        //设置每批次插入多少条数据
        int batchSize=10000;
        int count = (list.size() + batchSize - 1) / batchSize; // 计算总批次数量,确保最后一个批次也能处理
        //保存单批提交的数据集合
        List<SysFile> oneBatchList = new ArrayList<>(batchSize); // 预分配容量

​​​​​​​        for (int i = 0; i < count; i++) {
            int startIndex = i * batchSize;
            int endIndex = Math.min(startIndex + batchSize, list.size());
            oneBatchList.addAll(list.subList(startIndex, endIndex));
            fileMapper.insertBatchSomeColumn(oneBatchList);
            oneBatchList.clear(); // 清空集合以备下次循环使用
        }编程
    }

【TIPS】

为了确保批量插入的高效性,还需要进行一些配置和优化。例如,在application.yml中配置数据库连接时,可以开启MySQL的批处理模式

【rewriteBatchedStatements=true】:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/testBtach?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

此外还可以考虑使用jdbcTemplate.batchUpdate、Spring Batch来实现(这两种未测试)。

到此这篇关于SpringBoot整合mybatisPlus实现批量插入并获取ID详解的文章就介绍到这了,更多相关SpringBoot整合mybatisPlus插入ID内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于SpringBoot整合mybatisPlus实现批量插入并获取ID详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1154406

相关文章

HTML5 搜索框Search Box详解

《HTML5搜索框SearchBox详解》HTML5的搜索框是一个强大的工具,能够有效提升用户体验,通过结合自动补全功能和适当的样式,可以创建出既美观又实用的搜索界面,这篇文章给大家介绍HTML5... html5 搜索框(Search Box)详解搜索框是一个用于输入查询内容的控件,通常用于网站或应用程

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal