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

Mybatis-Plus通過SQL注入器實現(xiàn)批量插入的實踐

 更新時間:2022年08月11日 10:24:35   作者:斗者_(dá)2013  
本文主要介紹了Mybatis-Plus通過SQL注入器實現(xiàn)批量插入的實踐,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

批量插入是實際工作中常見的一個功能,mysql支持一條sql語句插入多條數(shù)據(jù)。但是Mybatis-Plus中默認(rèn)提供的saveBatch方法并不是真正的批量插入,而是遍歷實體集合每執(zhí)行一次insert語句插入一條記錄。相比批量插入,性能上顯然會差很多。
今天談一下,在Mybatis-Plus中如何通過SQL注入器實現(xiàn)真正的批量插入。

一、mysql批量插入的支持

insert批量插入的語法支持:

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

二、Mybatis-Plus默認(rèn)saveBatch方法解析

1、測試工程建立

測試的數(shù)據(jù)表:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL COMMENT '主鍵ID',
  `name` varchar(30) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年齡',
  `email` varchar(50) DEFAULT NULL COMMENT '郵箱',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

在IDEA中配置好數(shù)據(jù)庫連接,并安裝好MybatisX-Generator插件,生成對應(yīng)表的model、mapper、service、xml文件。

生成的文件推薦保存在工程目錄下,generator目錄下。先生成文件,用戶根據(jù)自己的需要,再將文件移動到指定目錄,這樣避免出現(xiàn)文件覆蓋。

生成實體的配置選項,這里我勾選了Lombok和Mybatis-Plus3,生成的類更加優(yōu)雅。

移動生成的文件到對應(yīng)目錄:

由于都是生成的代碼,這里就不補充代碼了。

2、默認(rèn)批量插入saveBatch方法測試

    @Test
    public void testBatchInsert() {
        System.out.println("----- batch insert method test ------");
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("test");
            user.setAge(13);
            user.setEmail("101@qq.com");
            list.add(user);
        }
        userService.saveBatch(list);
    }

執(zhí)行日志:

顯然,這里每次執(zhí)行insert操作,都只插入了一條數(shù)據(jù)。

3、saveBatch方法實現(xiàn)分析

//批量保存的方法,做了分批請求處理,默認(rèn)一次處理1000條數(shù)據(jù)
default boolean saveBatch(Collection<T> entityList) {
    return this.saveBatch(entityList, 1000);
}

//用戶也可以自己指定每批處理的請求數(shù)量
boolean saveBatch(Collection<T> entityList, int batchSize);
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
    Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]);
    return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, (sqlSession) -> {
        int size = list.size();
        int idxLimit = Math.min(batchSize, size);
        int i = 1;

        for(Iterator var7 = list.iterator(); var7.hasNext(); ++i) {
            E element = var7.next();
            consumer.accept(sqlSession, element);
            //每次達(dá)到批次數(shù),sqlSession就刷新一次,進(jìn)行數(shù)據(jù)庫請求,生成Id
            if (i == idxLimit) {
                sqlSession.flushStatements();
                idxLimit = Math.min(idxLimit + batchSize, size);
            }
        }

    });
}

我們將批次數(shù)設(shè)置為3,用來測試executeBatch的處理機制。

    @Test
    public void testBatchInsert() {
        System.out.println("----- batch insert method test ------");
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("test");
            user.setAge(13);
            user.setEmail("101@qq.com");
            list.add(user);
        }
        //批次數(shù)設(shè)為3,用來測試
        userService.saveBatch(list,3);
    }

執(zhí)行結(jié)果,首批提交的請求,已經(jīng)生成了id,還沒有提交的id為null。
(這里的提交是sql請求,而不是說的事物提交)

小結(jié):
Mybatis-Plus中默認(rèn)的批量保存方法saveBatch,底層是通過sqlSession.flushStatements()將一個個單條插入的insert語句分批次進(jìn)行提交。
相比遍歷集合去調(diào)用userMapper.insert(entity),執(zhí)行一次提交一次,saveBatch批量保存有一定的性能提升,但從sql層面上來說,并不算是真正的批量插入。

補充:

遍歷集合單次提交的批量插入。

 @Test
    public void forEachInsert() {
        System.out.println("forEachInsert 插入開始========");
        long start = System.currentTimeMillis();
        for (int i = 0; i < list.size(); i++) {
            userMapper.insert(list.get(i));
        }
        System.out.println("foreach 插入耗時:"+(System.currentTimeMillis()-start));
    }

三、Mybatis-plus中SQL注入器介紹

SQL注入器官方文檔:https://baomidou.com/pages/42ea4a/

1.sqlInjector介紹

SQL注入器sqlInjector 用于注入 ISqlInjector 接口的子類,實現(xiàn)自定義方法注入。
參考默認(rèn)注入器 DefaultSqlInjector

Mybatis-plus默認(rèn)可以注入的方法如下,大家也可以參考其實現(xiàn)自己擴展:

默認(rèn)注入器DefaultSqlInjector的內(nèi)容:

public class DefaultSqlInjector extends AbstractSqlInjector {
    public DefaultSqlInjector() {
    }

    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        //注入通用的dao層接口的操作方法
        return (List)Stream.of(new Insert(), new Delete(), new DeleteByMap(), new DeleteById(), new DeleteBatchByIds(), new Update(), new UpdateById(), new SelectById(), new SelectBatchByIds(), new SelectByMap(), new SelectOne(), new SelectCount(), new SelectMaps(), new SelectMapsPage(), new SelectObjs(), new SelectList(), new SelectPage()).collect(Collectors.toList());
    }
}

2.擴展中提供的4個可注入方法實現(xiàn)

目前在mybatis-plus的擴展插件中com.baomidou.mybatisplus.extension,給我們額外提供了4個注入方法。

  • AlwaysUpdateSomeColumnById 根據(jù)Id更新每一個字段,全量更新不忽略null字段,解決mybatis-plus中updateById默認(rèn)會自動忽略實體中null值字段不去更新的問題。
  • InsertBatchSomeColumn 真實批量插入,通過單SQL的insert語句實現(xiàn)批量插入
  • DeleteByIdWithFill 帶自動填充的邏輯刪除,比如自動填充更新時間、操作人
  • Upsert 更新or插入,根據(jù)唯一約束判斷是執(zhí)行更新還是刪除,相當(dāng)于提供insert on duplicate key update支持
insert into t_name (uid, app_id,createTime,modifyTime)
values(111, 1000000,'2017-03-07 10:19:12','2017-03-07 10:19:12')
on duplicate key update uid=111, app_id=1000000, 
createTime='2017-03-07 10:19:12',modifyTime='2017-05-07 10:19:12'

mysql在存在主鍵沖突或者唯一鍵沖突的情況下,根據(jù)插入策略不同,一般有以下三種避免方法。

  • insert ignore
  • replace into
  • insert on duplicate key update

這里不展開介紹,大家可以自行查看:http://www.dbjr.com.cn/article/194579.htm

四、通過SQL注入器實現(xiàn)真正的批量插入

通過SQL注入器sqlInjector 增加批量插入方法InsertBatchSomeColumn的過程如下:

1.繼承DefaultSqlInjector擴展自定義的SQL注入器

代碼如下:

/**
 * 自定義Sql注入
 */
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;
    }
}

2.將自定義的SQL注入器注入到Mybatis容器中

代碼如下:

@Configuration
public class MybatisPlusConfig {

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

3.繼承 BaseMapper 添加自定義方法

public interface CommonMapper<T> extends BaseMapper<T> {
    /**
     * 全量插入,等價于insert
     * @param entityList
     * @return
     */
    int insertBatchSomeColumn(List<T> entityList);
}

4.Mapper層接口繼承新的CommonMapper

public interface UserMapper extends CommonMapper<User> {

}

5.單元測試

 @Test
    public void testBatchInsert() {
        System.out.println("----- batch insert method test ------");
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("test");
            user.setAge(13);
            user.setEmail("101@qq.com");
            list.add(user);
        }
        userMapper.insertBatchSomeColumn(list);
    }

執(zhí)行結(jié)果:

可以看到已經(jīng)實現(xiàn)單條insert語句支持?jǐn)?shù)據(jù)的批量插入。

注意??:
默認(rèn)的insertBatchSomeColumn實現(xiàn)中,并沒有類似saveBatch中的分配提交處理,
這就存在一個問題,如果出現(xiàn)一個非常大的集合,就會導(dǎo)致最后組裝提交的insert語句的長度超過mysql的限制。

6.insertBatchSomeColumn添加分批處理機制

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private UserMapper userMapper;

    /**
     * 采用insertBatchSomeColumn重寫saveBatch方法,保留分批處理機制
     * @param entityList
     * @param batchSize
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean saveBatch(Collection<User> entityList, int batchSize) {
        try {
            int size = entityList.size();
            int idxLimit = Math.min(batchSize, size);
            int i = 1;
            //保存單批提交的數(shù)據(jù)集合
            List<User> oneBatchList = new ArrayList<>();
            for(Iterator<User> var7 = entityList.iterator(); var7.hasNext(); ++i) {
                User element = var7.next();
                oneBatchList.add(element);
                if (i == idxLimit) {
                    userMapper.insertBatchSomeColumn(oneBatchList);
                    //每次提交后需要清空集合數(shù)據(jù)
                    oneBatchList.clear();
                    idxLimit = Math.min(idxLimit + batchSize, size);
                }
            }
        }catch (Exception e){
            log.error("saveBatch fail",e);
            return false;
        }
        return  true;
    }

更好的實現(xiàn)是繼承ServiceImpl實現(xiàn)類,自己擴展通用的服務(wù)實現(xiàn)類,在其中重寫通用的saveBatch方法,這樣就不用在每一個服務(wù)類中都重寫一遍saveBatch方法。

單元測試:

    @Test
    public void testBatchInsert() {
        System.out.println("----- batch insert method test ------");
        List<User> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("test");
            user.setAge(13);
            user.setEmail("101@qq.com");
            list.add(user);
        }
        //批次數(shù)設(shè)為3,用來測試
        userService.saveBatch(list,3);
    }

執(zhí)行結(jié)果:

分4次采用insert批量新增,符合我們的結(jié)果預(yù)期。

總結(jié)

本文主要介紹了Mybatis-Plus中如何通過SQL注入器實現(xiàn)真正的批量插入。主要掌握如下內(nèi)容:
1、了解Mybatis-Plus中SQL注入器有什么作用,如何去進(jìn)行擴展。
2、默認(rèn)的4個擴展方法各自的作用。
3、默認(rèn)的saveBatch批量新增和通過insertBatchSomeColumn實現(xiàn)的批量新增的底層實現(xiàn)原理的區(qū)別,為什么insertBatchSomeColumn性能更好以及存在哪些弊端。
4、為insertBatchSomeColumn添加分批處理機制,避免批量插入的insert語句過長問題。

到此這篇關(guān)于Mybatis-Plus通過SQL注入器實現(xiàn)批量插入的實踐的文章就介紹到這了,更多相關(guān)Mybatis-Plus SQL注入器批量插入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java在PowerPoint幻燈片中創(chuàng)建散點圖的方法

    Java在PowerPoint幻燈片中創(chuàng)建散點圖的方法

    散點圖是通過兩組數(shù)據(jù)構(gòu)成多個坐標(biāo)點,考察坐標(biāo)點的分布,判斷兩變量之間是否存在某種關(guān)聯(lián)或總結(jié)坐標(biāo)點的分布模式,這篇文章主要介紹了Java如何在PowerPoint幻燈片中創(chuàng)建散點圖,需要的朋友可以參考下
    2023-04-04
  • Mybatis攔截器實現(xiàn)自定義需求

    Mybatis攔截器實現(xiàn)自定義需求

    本文主要介紹了Mybatis攔截器實現(xiàn)自定義需求,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 基于java實現(xiàn)websocket協(xié)議過程詳解

    基于java實現(xiàn)websocket協(xié)議過程詳解

    這篇文章主要介紹了基于java實現(xiàn)websocket協(xié)議過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • IDEA創(chuàng)建方法時如何快速添加注釋

    IDEA創(chuàng)建方法時如何快速添加注釋

    這篇文章主要介紹了IDEA創(chuàng)建方法時如何快速添加注釋問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java中IO流 RandomAccessFile類實例詳解

    Java中IO流 RandomAccessFile類實例詳解

    這篇文章主要介紹了Java中IO流 RandomAccessFile類實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 教你利用springboot集成swagger并生成接口文檔

    教你利用springboot集成swagger并生成接口文檔

    有很多小伙伴不會利用springboot集成swagger并生成接口文檔,今天特地整理了這篇文章,文中有非常詳細(xì)的代碼圖文介紹及代碼示例,對不會這個方法的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • 淺談java的byte數(shù)組的不同寫法

    淺談java的byte數(shù)組的不同寫法

    下面小編就為大家?guī)硪黄獪\談java的byte數(shù)組的不同寫法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • SpringCloud中的服務(wù)接口(api)

    SpringCloud中的服務(wù)接口(api)

    這篇文章主要介紹了SpringCloud中的服務(wù)接口(api),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 詳細(xì)聊聊Spring MVC重定向與轉(zhuǎn)發(fā)

    詳細(xì)聊聊Spring MVC重定向與轉(zhuǎn)發(fā)

    大家應(yīng)該都知道請求重定向和請求轉(zhuǎn)發(fā)都是web開發(fā)中資源跳轉(zhuǎn)的方式,這篇文章主要給大家介紹了關(guān)于Spring MVC重定向與轉(zhuǎn)發(fā)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • Java實現(xiàn)獲取cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)等信息的方法示例

    Java實現(xiàn)獲取cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)等信息的方法示例

    這篇文章主要介紹了Java實現(xiàn)獲取cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)等信息的方法,涉及java使用第三方j(luò)ar包針對本機硬件的cpu、內(nèi)存、硬盤、網(wǎng)絡(luò)信息等的讀取相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06

最新評論