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

相关文章

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

利用python实现对excel文件进行加密

《利用python实现对excel文件进行加密》由于文件内容的私密性,需要对Excel文件进行加密,保护文件以免给第三方看到,本文将以Python语言为例,和大家讲讲如何对Excel文件进行加密,感兴... 目录前言方法一:使用pywin32库(仅限Windows)方法二:使用msoffcrypto-too

SpringBoot整合OpenFeign的完整指南

《SpringBoot整合OpenFeign的完整指南》OpenFeign是由Netflix开发的一个声明式Web服务客户端,它使得编写HTTP客户端变得更加简单,本文为大家介绍了SpringBoot... 目录什么是OpenFeign环境准备创建 Spring Boot 项目添加依赖启用 OpenFeig

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

C#使用StackExchange.Redis实现分布式锁的两种方式介绍

《C#使用StackExchange.Redis实现分布式锁的两种方式介绍》分布式锁在集群的架构中发挥着重要的作用,:本文主要介绍C#使用StackExchange.Redis实现分布式锁的... 目录自定义分布式锁获取锁释放锁自动续期StackExchange.Redis分布式锁获取锁释放锁自动续期分布式

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

SpringBoot中配置文件的加载顺序解读

《SpringBoot中配置文件的加载顺序解读》:本文主要介绍SpringBoot中配置文件的加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot配置文件的加载顺序1、命令⾏参数2、Java系统属性3、操作系统环境变量5、项目【外部】的ap

使用Python实现矢量路径的压缩、解压与可视化

《使用Python实现矢量路径的压缩、解压与可视化》在图形设计和Web开发中,矢量路径数据的高效存储与传输至关重要,本文将通过一个Python示例,展示如何将复杂的矢量路径命令序列压缩为JSON格式,... 目录引言核心功能概述1. 路径命令解析2. 路径数据压缩3. 路径数据解压4. 可视化代码实现详解1

python获取网页表格的多种方法汇总

《python获取网页表格的多种方法汇总》我们在网页上看到很多的表格,如果要获取里面的数据或者转化成其他格式,就需要将表格获取下来并进行整理,在Python中,获取网页表格的方法有多种,下面就跟随小编... 目录1. 使用Pandas的read_html2. 使用BeautifulSoup和pandas3.