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

Mybatis-Plus多種批量插入方案對(duì)比小結(jié)

 更新時(shí)間:2024年10月31日 10:36:49   作者:北i  
在項(xiàng)目中優(yōu)化Mybatis-Plus批量插入性能是關(guān)鍵,通過(guò)比較不同方案,本文就來(lái)介紹一下Mybatis-Plus多種批量插入方案對(duì)比小結(jié),感興趣都的可以了解一下

背景

六月某日上線了一個(gè)日?qǐng)?bào)表任務(wù),因是第一次上線,故需要為歷史所有日期都初始化一次報(bào)表數(shù)據(jù)
在執(zhí)行過(guò)程中發(fā)現(xiàn)新增特別的慢:插入十萬(wàn)條左右的數(shù)據(jù),SQL執(zhí)行耗費(fèi)高達(dá)三分多鐘

因很早就聽聞過(guò)mybatis-plus的[偽]批量新增的問(wèn)題,很快鎖定問(wèn)題并進(jìn)行修復(fù),下面細(xì)節(jié)描述多種批量新增方案的具體性能表現(xiàn)

# 測(cè)試表結(jié)構(gòu)
DROP TABLE IF EXISTS `biz_batch_insert_test`;
CREATE TABLE `biz_batch_insert_test` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(600) DEFAULT NULL,
  `age` tinyint(4) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

# name字段給的長(zhǎng)度大了些,模擬生產(chǎn)實(shí)際表結(jié)構(gòu)占用
# 測(cè)試庫(kù)版本:5.7.5

方案一:傳統(tǒng)for循環(huán)

@Test
public void testUserInsert() {
    long l = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        TestUser testUser = new TestUser();
        testUser.setName("中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)");
        testUser.setAge(20);
        testUserService.save(testUser);
    }
    System.out.println("毫秒==>" + (System.currentTimeMillis() - l));
}

# 插入10萬(wàn)條耗時(shí):238040ms,大約4分鐘

方案二:使用Mybatis-Plus的saveBatch

@Test
public void testUserInsert() {
    long l = System.currentTimeMillis();
    List<TestUser> list = new ArrayList<>();
    for (int i = 0; i < 100000; i++) {
        TestUser testUser = new TestUser();
        testUser.setName("中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)");
        testUser.setAge(20);
        list.add(testUser);
    }
    testUserService.saveBatch(list);
    System.out.println("毫秒==>" + (System.currentTimeMillis() - l));
}

# 插入耗時(shí):62180ms,大約1分鐘

這里先留下一張saveBatch的SQL日志截圖,這里的日志是一個(gè)insert into語(yǔ)句,下面帶了一千條數(shù)據(jù)(MP默認(rèn)一千條一個(gè)批次),使用Mybatis Log插件查看還是單條的SQL

方案三:在方案二的基礎(chǔ)上修改MySQL連接參數(shù):rewriteBatchedStatements=true

# 與方案二測(cè)試代碼相同
# 插入耗時(shí):35260ms,大約半分鐘

其SQL日志也如上方案二所示,MySQL Jdbc驅(qū)動(dòng)在默認(rèn)情況下會(huì)無(wú)視executeBatch()語(yǔ)句,把我們期望批量執(zhí)行的一組sql語(yǔ)句拆散,一條一條地發(fā)給MySQL數(shù)據(jù)庫(kù),直接造成較低的性能
Mysql連接配置鏈接

方案四:使用Mybatis-Plus提供的擴(kuò)展插件:InsertBatchSomeColumn

@Test
public void testUserInsert() {
    long l = System.currentTimeMillis();
    List<TestUser> list = new ArrayList<>();
    for (int i = 0; i < 10000; i++) {
        TestUser testUser = new TestUser();
        testUser.setName("中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)中國(guó)");
        testUser.setAge(20);
        list.add(testUser);
        // 因?yàn)閙ysql的參數(shù)max_allowed_packet限制,所以這里程序改成單批1000條
        if(list.size() == 1000){
            testUserMapper.insertBatchSomeColumn(list);
            list.clear();
        }
    }
    System.out.println("毫秒==>" + (System.currentTimeMillis() - l));
}

# 插入耗時(shí):24410ms,大約24秒

再來(lái)看看此時(shí)控制臺(tái)的SQL,與方案二的SQL有著明顯的區(qū)別,這里是將批次插入的數(shù)據(jù)拼接在同一條SQL中,對(duì)于MySQL處理來(lái)說(shuō),這是真的批量新增

配置方式

// 1. 自定義SQL注入器
public class BatchSaveSqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        // 注意:保留mybatis-plus的自帶方法
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
        methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
        return methodList;
    }
}

// 2. 實(shí)現(xiàn)自定義baseMapper
public interface BatchSaveBaseMapper<T> extends BaseMapper<T> {
    /**
     * 批量插入 僅適用于mysql
     *
     * @param entityList
     *            實(shí)體列表
     * @return 影響行數(shù)
     */
    Integer insertBatchSomeColumn(Collection<T> entityList);
}



// 3. 注入插件
// 方式一
@Configuration
public class MybatisPlusConfig {
    /**
     * 分頁(yè)插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
    /**
     * SQL注入器
     */
    @Bean
    public BatchSaveSqlInjector easySqlInjector() {
        return new BatchSaveSqlInjector();
    }
}

// 方式二
// 若項(xiàng)目有自定義SqlSessionFactory,也可在初始化時(shí)將自定義SQL注入器植入,參考下圖MybatisPlusAutoConfiguration.sqlSessionFactory的做法

總結(jié)

插入10萬(wàn)數(shù)據(jù)耗時(shí)(秒)
mybatis-plus:save238
mybatis-plus的saveBatch:rewriteBatchedStatements=false62
mybatis-plus的saveBatch:rewriteBatchedStatements=true35
mybatis-plus擴(kuò)展插件:InsertBatchSomeColumn24

到此這篇關(guān)于Mybatis-Plus多種批量插入方案對(duì)比小結(jié)的文章就介紹到這了,更多相關(guān)Mybatis-Plus多種批量插入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • java線程池ExecutorService超時(shí)處理小結(jié)

    java線程池ExecutorService超時(shí)處理小結(jié)

    使用ExecutorService時(shí),設(shè)置子線程執(zhí)行超時(shí)是一個(gè)常見(jiàn)需求,本文就來(lái)詳細(xì)的介紹一下ExecutorService超時(shí)的三種方法,感興趣的可以了解一下
    2024-09-09
  • 基于Transactional事務(wù)的使用以及注意說(shuō)明

    基于Transactional事務(wù)的使用以及注意說(shuō)明

    這篇文章主要介紹了Transactional事務(wù)的使用以及注意說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 詳解Java線程池的使用(7種創(chuàng)建方法)

    詳解Java線程池的使用(7種創(chuàng)建方法)

    這篇文章主要介紹了詳解Java線程池的使用(7種創(chuàng)建方法),線程池的創(chuàng)建?式總共包含7種,其中6種是通過(guò)Executors創(chuàng)建的,1種是通過(guò)ThreadPoolExecutor創(chuàng)建的,今天我們就來(lái)詳細(xì)說(shuō)一下
    2023-03-03
  • Java停止線程的3種方法

    Java停止線程的3種方法

    這篇文章主要分享Java停止線程的3種方法,分別是自定義中斷標(biāo)識(shí)符,停止線程、使用線程中斷方法interrupt停止線程、使用stop停止線程。下文詳細(xì)介紹需要的小伙伴可以參考一下
    2022-05-05
  • java實(shí)現(xiàn)簡(jiǎn)單發(fā)送郵件功能

    java實(shí)現(xiàn)簡(jiǎn)單發(fā)送郵件功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單發(fā)送郵件功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Spring Boot中整合Spring Security并自定義驗(yàn)證代碼實(shí)例

    Spring Boot中整合Spring Security并自定義驗(yàn)證代碼實(shí)例

    本篇文章主要介紹了Spring Boot中整合Spring Security并自定義驗(yàn)證代碼實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Java?SE判斷兩個(gè)文件內(nèi)容是否相同的多種方法代碼

    Java?SE判斷兩個(gè)文件內(nèi)容是否相同的多種方法代碼

    昨天因?yàn)橐獛蛶熜值拿λ钥戳艘幌氯绾闻袛鄡蓚€(gè)文件內(nèi)容是否相同,這里給大家總結(jié)下,這篇文章主要給大家介紹了關(guān)于Java?SE判斷兩個(gè)文件內(nèi)容是否相同的多種方法,需要的朋友可以參考下
    2023-11-11
  • maven環(huán)境變量配置以及失敗原因解析

    maven環(huán)境變量配置以及失敗原因解析

    這篇文章主要為大家詳細(xì)介紹了maven環(huán)境變量配置教程,以及為大家解析了安裝失敗的原因,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Springboot集成規(guī)則引擎Drools方式

    Springboot集成規(guī)則引擎Drools方式

    這篇文章主要介紹了Springboot集成規(guī)則引擎Drools方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • java實(shí)現(xiàn)用戶自動(dòng)登錄

    java實(shí)現(xiàn)用戶自動(dòng)登錄

    這篇文章主要為大家詳細(xì)介紹了java用戶自動(dòng)登錄的實(shí)現(xiàn)方法,分為六個(gè)步驟實(shí)現(xiàn)用戶自動(dòng)登錄,并驗(yàn)證用戶是否已經(jīng)登錄,感興趣的小伙伴們可以參考一下
    2016-03-03

最新評(píng)論