欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot整合mybatisPlus實現(xiàn)批量插入并獲取ID詳解

 更新時間:2025年04月27日 15:11:52   作者:流煙默  
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何整合mybatisPlus實現(xiàn)批量插入并獲取ID,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

背景:需要實現(xiàn)批量插入并且得到插入后的ID。

使用for循環(huán)進行insert這里就不說了,在海量數(shù)據(jù)下其性能是最慢的。數(shù)據(jù)量小的情況下,沒什么區(qū)別。

【1】saveBatch(一萬條數(shù)據(jù)總耗時: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);
 }

我們分析其實現(xiàn)原理如下: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);
    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;
}

其實也就是一條條插入。

【2】集合方式foreach(一萬條數(shù)據(jù)總耗時:474ms)

SysFileMapper 自定義方法batchSaveFiles

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

xml實現(xiàn)

<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"));
    fileMapper.batchSaveFiles(list);
    System.out.println(list);
}

測試結(jié)果:

注意:這種方式得不到ID哦!

【3】MyBatis-Plus提供的InsertBatchSomeColumn方法(一萬條數(shù)據(jù)總耗時:690ms)

這里mybatisplus版本是3.3.0。

編寫MySqlInjector

public class MySqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        //更新時自動填充的字段,不用插入值
        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 表達(dá)式作為參數(shù),該表達(dá)式用于過濾字段,只保留那些 getFieldFill 屬性不是 FieldFill.UPDATE 的字段。

第二個 InsertBatchSomeColumn 方法沒有參數(shù),表示不進行任何過濾,直接插入所有字段。

注入到配置類

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

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

SysFileMapper 自定義方法

public interface SysFileMapper extends BaseMapper<SysFile> {

    int insertBatchSomeColumn(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);
}

測試結(jié)果

這里不僅實現(xiàn)了【2】的效果,還可以得到插入后的ID。

【4】假設(shè)一萬條/十萬條數(shù)據(jù)的情況下,執(zhí)行時間是多少

策略一萬條十萬條
方式一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("一萬條數(shù)據(jù)總耗時:"+(end-start)+"ms");
    }

一萬條數(shù)據(jù)總耗時:2478ms

十萬條數(shù)據(jù)總耗時: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("一萬條數(shù)據(jù)總耗時:"+(end-start)+"ms");
 }

一萬條數(shù)據(jù)總耗時:474ms

十萬條數(shù)據(jù)總耗時: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("一萬條數(shù)據(jù)總耗時:"+(end-start)+"ms");
}

一萬條數(shù)據(jù)總耗時:690ms

十萬條數(shù)據(jù)總耗時:8339ms

【5】百萬條數(shù)據(jù)的情況下進行優(yōu)化

方式二、方式三都是拼接為一條SQL,也就說有多少直接全部一次性插入,這就可能會導(dǎo)致最后的 sql 拼接語句特別長,超出了mysql 的限制。

這是什么意思呢?以MySQL為例,我們是需要考慮 max_allowed_packet 這個屬性配置大小。其決定了你最大可以單次發(fā)送包的大小,這里可以修改為64M也就是 67108864。

但是這個不是最優(yōu)解,最優(yōu)解應(yīng)該是控制每次插入的數(shù)量,比如一萬條插入一次。

    @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);
        }
        //設(shè)置每批次插入多少條數(shù)據(jù)
        int batchSize=10000;
        int count = (list.size() + batchSize - 1) / batchSize; // 計算總批次數(shù)量,確保最后一個批次也能處理
        //保存單批提交的數(shù)據(jù)集合
        List<SysFile> oneBatchList = new ArrayList<>(batchSize); // 預(yù)分配容量

???????        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(); // 清空集合以備下次循環(huán)使用
        }
    }

【TIPS】

為了確保批量插入的高效性,還需要進行一些配置和優(yōu)化。例如,在application.yml中配置數(shù)據(jù)庫連接時,可以開啟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來實現(xiàn)(這兩種未測試)。

到此這篇關(guān)于SpringBoot整合mybatisPlus實現(xiàn)批量插入并獲取ID詳解的文章就介紹到這了,更多相關(guān)SpringBoot整合mybatisPlus插入ID內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式實現(xiàn)方法詳解

    Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式實現(xiàn)方法詳解

    這篇文章主要介紹了Java中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式實現(xiàn)方法,結(jié)合實例形式分析了Java中綴表達(dá)式轉(zhuǎn)換成后綴表達(dá)式的相關(guān)算法原理與具體實現(xiàn)技巧,需要的朋友可以參考下
    2019-03-03
  • Java中通過Class類獲取Class對象的方法詳解

    Java中通過Class類獲取Class對象的方法詳解

    這篇文章主要給大家介紹了關(guān)于Java中通過Class類獲取Class對象的方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • Java中this和super的區(qū)別及this能否調(diào)用到父類使用

    Java中this和super的區(qū)別及this能否調(diào)用到父類使用

    這篇文章主要介紹了Java中this和super的區(qū)別及this能否調(diào)用到父類使用,this和super都是Java中常見的關(guān)鍵字,下文關(guān)于兩者區(qū)別介紹,需要的小伙伴可以參考一下
    2022-05-05
  • Java實現(xiàn)批量化操作Excel文件的示例代碼

    Java實現(xiàn)批量化操作Excel文件的示例代碼

    在操作Excel的場景中,通常會有一些針對Excel的批量操作,這篇文章主要為大家詳細(xì)介紹了如何使用GcExcel實現(xiàn)批量化操作Excel,感興趣的可以了解一下
    2024-12-12
  • Java8在遍歷集合時刪除元素問題解決

    Java8在遍歷集合時刪除元素問題解決

    本文主要介紹了Java8在遍歷集合時刪除元素問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java基礎(chǔ)學(xué)習(xí)之標(biāo)簽

    Java基礎(chǔ)學(xué)習(xí)之標(biāo)簽

    在Java中,標(biāo)簽必須在循環(huán)之前使用, 一個循環(huán)之中嵌套另一個循環(huán)的開關(guān),從多重嵌套中continue或break,該文詳細(xì)介紹了標(biāo)簽的相關(guān)知識,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們還很有幫助,需要的朋友可以參考下
    2021-05-05
  • 詳解JDBC使用

    詳解JDBC使用

    JDBC(Java Database Connectivity),即Java數(shù)據(jù)庫連接,是一種用于執(zhí)行SQL語句的Java API,可以為多種關(guān)系數(shù)據(jù)庫提供同一訪問,它由一組用Java語言編寫的類和接口組成。
    2017-05-05
  • Springcloud eureka搭建高可用集群過程圖解

    Springcloud eureka搭建高可用集群過程圖解

    這篇文章主要介紹了Springcloud eureka搭建高可用集群過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • 淺談spring使用策略模式實現(xiàn)多種場景登錄方式

    淺談spring使用策略模式實現(xiàn)多種場景登錄方式

    本文主要介紹了spring使用策略模式實現(xiàn)多種場景登錄方式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 使用 Java 開發(fā) Gradle 插件的步驟

    使用 Java 開發(fā) Gradle 插件的步驟

    這篇文章主要介紹了使用 Java 開發(fā) Gradle 插件的步驟,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-03-03

最新評論