最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis實(shí)現(xiàn)插入大量數(shù)據(jù)方法詳解

 更新時(shí)間:2022年11月21日 10:27:35   作者:小學(xué)生波波  
最近在公司項(xiàng)目開(kāi)發(fā)中遇到批量數(shù)據(jù)插入或者更新,下面這篇文章主要給大家介紹了關(guān)于MyBatis實(shí)現(xiàn)批量插入的相關(guān)資料,需要的朋友可以參考下

1、前言

在開(kāi)發(fā)過(guò)程中,有時(shí)我們會(huì)碰到將大批量的數(shù)據(jù)入庫(kù)的場(chǎng)景,那么我們一般有下面三種方式入庫(kù):

  • ExecutorType.BATCH批處理方式插入
  • foreach循環(huán)標(biāo)簽插入
  • MyBatisPlus自帶的saveBatch批量新增方法

下面我們用一個(gè)案例來(lái)測(cè)試一下,看下三種方式哪種效率最好

2、案例說(shuō)明

現(xiàn)在我數(shù)據(jù)庫(kù)新建一張表t_user,建表語(yǔ)句如下:

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',
  `age` int(11) NULL DEFAULT NULL COMMENT '年齡',
  `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手機(jī)號(hào)',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用戶表' ROW_FORMAT = DYNAMIC;

我這里MySQL數(shù)據(jù)庫(kù)版本是5.5.28

然后我用上面三種方式分別向t_user表中存5萬(wàn)條數(shù)據(jù),每次存數(shù)據(jù)前,先清空一下表數(shù)據(jù),使用下面語(yǔ)句快速清除表數(shù)據(jù):

truncate table t_user;

每種方式我都測(cè)試5次,然后每種方式我都計(jì)算一個(gè)耗時(shí)平均值,看哪種方式耗時(shí)最小

3、編碼

這是我的基礎(chǔ)項(xiàng)目:https://gitee.com/colinWu_java/spring-boot-base.git

我會(huì)在此基礎(chǔ)項(xiàng)目上做測(cè)試

3.1、ExecutorType.BATCH批處理方式插入

ExecutorType.BATCH介紹:

  • Mybatis內(nèi)置的ExecutorType有3種,SIMPLE、REUSE、BATCH,默認(rèn)的是simple,該模式下它為每個(gè)語(yǔ)句的執(zhí)行創(chuàng)建一個(gè)新的預(yù)處理語(yǔ)句,單條提交sql
  • 而batch模式重復(fù)使用已經(jīng)預(yù)處理的語(yǔ)句,并且批量執(zhí)行所有更新語(yǔ)句,顯然batch性能將更優(yōu);但batch模式也有自己的問(wèn)題,比如在Insert操作時(shí),在事務(wù)沒(méi)有提交之前,是沒(méi)有辦法獲取到自增的id,這在某型情形下是不符合業(yè)務(wù)要求的
  • 通過(guò)批處理的方式,我們就可以在 JDBC 客戶端緩存多條 SQL 語(yǔ)句,然后在 flush 或緩存滿的時(shí)候,將多條 SQL 語(yǔ)句打包發(fā)送到數(shù)據(jù)庫(kù)執(zhí)行,這樣就可以有效地降低上述兩方面的損耗,從而提高系統(tǒng)性能

下面開(kāi)始編碼

在UserController新增下面接口

/**
     * 測(cè)試大批量數(shù)據(jù)插入數(shù)據(jù)庫(kù)
     * 方式1:用一個(gè) for 循環(huán),把數(shù)據(jù)一條一條的插入
     * @return
     */
@GetMapping("/insertUser1/{count}")
public JSONResult insertUser1(@PathVariable("count") Integer count){
    return userService.insertUser1(count);
}

userService代碼:

public JSONResult insertUser1(Integer count) {
    //如果自動(dòng)提交設(shè)置為true,將無(wú)法控制提交的條數(shù)。所以我這里設(shè)置為false,,改為統(tǒng)一提交
    SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    UserMapper uMapper = session.getMapper(UserMapper.class);
    //獲取測(cè)試用戶集合數(shù)據(jù)
    List<User> userList = Tools.getUserList(count);
    int commitCount = 5000;//每次提交的數(shù)量條數(shù)
    long startTime = System.currentTimeMillis();
    for(int i=0; i<userList.size(); i++){
        uMapper.addUserOne(userList.get(i));
        if (i != 0 && i % commitCount == 0) {
            session.commit();
        }
    }
    session.commit();
    long endTime = System.currentTimeMillis();
    log.info("方式1耗時(shí):{}", (endTime - startTime));
    return JSONResult.success();
}

在UserMapper中新增addUserOne方法:

Integer addUserOne(User user);

對(duì)應(yīng)xml代碼:

<insert id="addUserOne">
    insert into t_user (name, age, phone) values (#{name}, #{age}, #{phone})
</insert>

getUserList方法代碼如下,就是獲取指定數(shù)量的測(cè)試用戶數(shù)據(jù)而已:

/**
     * 獲取指定數(shù)量的用戶測(cè)試對(duì)象
     * @param count 數(shù)量
     * @return
     */
public static List<User> getUserList(int count){
    List<User> userList = new ArrayList<>();
    User user = null;
    for(int i=1; i<=count; i++){
        user = new User();
        user.setName("王天霸" + i + "號(hào)");
        user.setAge(i);
        user.setAge(i);
        user.setPhone("18022222222");
        userList.add(user);
    }
    return userList;
}

注意事項(xiàng):

如果單次提交給MySQL數(shù)據(jù)庫(kù)的數(shù)據(jù)量太大的話,可能會(huì)報(bào)如下錯(cuò)誤:

com.mysql.jdbc.PacketTooBigException: Packet for query is too large (204444558 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.

出現(xiàn)這個(gè)錯(cuò)誤的原因是:

大數(shù)據(jù)量的插入或更新會(huì)被 max_allowed_packet 參數(shù)限制,導(dǎo)致失敗,因?yàn)镸ySQL根據(jù)配置文件會(huì)限制server允許接收的數(shù)據(jù)包大小

解決方案:

修改MySQL的配置參數(shù)

打開(kāi)Mysql命令客戶端:

然后輸入密碼之后輸入下面命令:

show VARIABLES like '%max_allowed_packet%';

結(jié)果:

用這個(gè)值除以1024*1024等于200M,那我這里就是設(shè)置的200M,根據(jù)實(shí)際情況設(shè)置該值,執(zhí)行如下命令即可:

set global max_allowed_packet = 200*1024*1024;

設(shè)置完成之后,需要關(guān)閉MySQL服務(wù),然后再重啟(注意,這里最大設(shè)置為:1G)

重啟成功后,需要關(guān)掉上面的MySQL命令客戶端,再重新打開(kāi)一次,查看是否設(shè)置成功

注意:

  • MySQL的JDBC連接的url中要加rewriteBatchedStatements參數(shù),并保證5.1.13以上版本的驅(qū)動(dòng),才能實(shí)現(xiàn)高性能的批量插入
  • MySQL JDBC驅(qū)動(dòng)在默認(rèn)情況下會(huì)無(wú)視executeBatch()語(yǔ)句,把我們期望批量執(zhí)行的一組SQL語(yǔ)句拆散,一條一條地發(fā)給MySQL數(shù)據(jù)庫(kù),批量插入實(shí)際上是單條插入,直接造成較低的性能
  • 只有把rewriteBatchedStatements參數(shù)置為true,驅(qū)動(dòng)才會(huì)幫你批量執(zhí)行SQL,另外這個(gè)選項(xiàng)對(duì)INSERT/UPDATE/DELETE都有效

url: jdbc:mysql://127.0.0.1:3306/test1?allowMultiQueries=true&rewriteBatchedStatements=true
//allowMultiQueries=true,允許一次性執(zhí)行多條SQL,批量插入時(shí)必須在連接地址后面加allowMultiQueries=true這個(gè)參數(shù)
//rewriteBatchedStatements=true,批量將數(shù)據(jù)傳給MySQL,數(shù)據(jù)庫(kù)會(huì)更高性能的執(zhí)行批量處理,MySQL數(shù)據(jù)庫(kù)版本在5.1.13以上,才能實(shí)現(xiàn)高性能的批量插入

3.2、foreach循環(huán)標(biāo)簽插入

UserController新增方法:

/**
     * 測(cè)試大批量數(shù)據(jù)插入數(shù)據(jù)庫(kù)
     * 方式2:foreach標(biāo)簽批量插入
     * @return
     */
@GetMapping("/insertUser2/{count}")
public JSONResult insertUser2(@PathVariable("count") Integer count){
    return userService.insertUser2(count);
}

insertUser2代碼:

public JSONResult insertUser2(Integer count) {
    //獲取測(cè)試用戶集合數(shù)據(jù)
    List<User> userList = Tools.getUserList(count);
    int countItem = 5000;//每次提交的記錄條數(shù)
    int userSize = userList.size();
    List<User> userListTemp = new ArrayList<>();
    long startTime = System.currentTimeMillis();
    for (int i = 0, n=userSize; i < n; i++) {
        User user= userList.get(i);
        userListTemp.add(user);
        if ((i>0 && i % countItem == 0) || i == userSize - 1) {
            //每5000條記錄提交一次
            userMapper.insertUserBatch(userListTemp);
            userListTemp.clear();
        }
    }
    long endTime = System.currentTimeMillis();
    log.info("方式2耗時(shí):{}", (endTime - startTime));
    return JSONResult.success();
}

UserMapper的insertUserBatch方法:

void insertUserBatch(@Param("userList") List<User> userList);

對(duì)應(yīng)xml代碼:

<insert id="insertUserBatch">
    insert into t_user (name, age, phone) values
    <foreach collection="userList" item="user" separator=",">
        (#{user.name}, #{user.age}, #{user.phone})
    </foreach>
</insert>

3.3、MyBatisPlus自帶的saveBatch批量新增方法

UserController新增方法:

@Autowired
public UserService userService;
/**
     * 測(cè)試大批量數(shù)據(jù)插入數(shù)據(jù)庫(kù)
     * 方式3:mybatisplus自帶的saveBatch批量新增方法
     * @return
     */
@GetMapping("/insertUser3/{count}")
public JSONResult insertUser3(@PathVariable("count") Integer count){
    //獲取測(cè)試用戶集合數(shù)據(jù)
    List<User> userList = Tools.getUserList(count);
    long startTime = System.currentTimeMillis();
    userService.saveBatch(userList, 5000);//每次往數(shù)據(jù)庫(kù)提交5000條數(shù)據(jù)
    long endTime = System.currentTimeMillis();
    log.info("方式3耗時(shí):{}", (endTime - startTime));
    return JSONResult.success();
}

4、測(cè)試

在瀏覽器中訪問(wèn)地址:http://localhost:8001/user/insertUser1/50000

這里的50000是表示插入5萬(wàn)條數(shù)據(jù)到t_user表

每次訪問(wèn)后,都記錄一下耗時(shí),然后清掉t_user表數(shù)據(jù),再訪問(wèn),反復(fù)測(cè)試5次

然后再訪問(wèn)http://localhost:8001/user/insertUser2/50000http://localhost:8001/user/insertUser2/50000

步驟和上面一致,最終我統(tǒng)計(jì)出來(lái)的結(jié)果如下:

很明顯,方式一效率最高

注意:以上結(jié)果僅是我本地測(cè)試情況,大家機(jī)器上可能會(huì)不同

5、總結(jié)

經(jīng)過(guò)今天的測(cè)試,我們知道批量插入數(shù)據(jù)最快的方式就是ExecutorType.BATCH批處理方式插入有些小的注意點(diǎn)記得在實(shí)際開(kāi)發(fā)中謹(jǐn)慎處理,比如url參數(shù)配置,還有提交數(shù)量不要太大

到此這篇關(guān)于MyBatis實(shí)現(xiàn)插入大量數(shù)據(jù)方法詳解的文章就介紹到這了,更多相關(guān)MyBatis插入大量數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 聊聊單線程的Redis為何會(huì)快到飛起

    聊聊單線程的Redis為何會(huì)快到飛起

    Redis想必大家都或多或少聽(tīng)過(guò)吧,我們?cè)诠ぷ鲗W(xué)習(xí)中通常用它來(lái)作為緩存使用,既然是作為緩存,大家的第一反應(yīng)肯定是:這家伙很快
    2022-02-02
  • java堆棧跟蹤工具jstack的使用教程

    java堆棧跟蹤工具jstack的使用教程

    jstack(stack?trace?for?java)是java虛擬機(jī)自帶的一種堆棧跟蹤工具,主要用于生成java虛擬機(jī)當(dāng)前時(shí)刻的線程快照,下面我們就來(lái)學(xué)習(xí)一下它的具體使用吧
    2023-11-11
  • 解決@Autowired注入static接口的問(wèn)題

    解決@Autowired注入static接口的問(wèn)題

    這篇文章主要介紹了解決@Autowired注入static接口的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java正則表達(dá)式判斷強(qiáng)密碼和隨機(jī)生成強(qiáng)密碼代碼示例

    java正則表達(dá)式判斷強(qiáng)密碼和隨機(jī)生成強(qiáng)密碼代碼示例

    這篇文章主要給大家介紹了關(guān)于java正則表達(dá)式判斷強(qiáng)密碼和隨機(jī)生成強(qiáng)密碼的相關(guān)資料,最近需要一個(gè)密碼強(qiáng)度正則表達(dá)式在用戶注冊(cè)時(shí)校驗(yàn)用戶密碼強(qiáng)度,需要的朋友可以參考下
    2023-08-08
  • java使用Dijkstra算法實(shí)現(xiàn)單源最短路徑

    java使用Dijkstra算法實(shí)現(xiàn)單源最短路徑

    這篇文章主要為大家詳細(xì)介紹了java使用Dijkstra算法實(shí)現(xiàn)單源最短路徑,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • JAVA使用爬蟲(chóng)抓取網(wǎng)站網(wǎng)頁(yè)內(nèi)容的方法

    JAVA使用爬蟲(chóng)抓取網(wǎng)站網(wǎng)頁(yè)內(nèi)容的方法

    這篇文章主要介紹了JAVA使用爬蟲(chóng)抓取網(wǎng)站網(wǎng)頁(yè)內(nèi)容的方法,實(shí)例分析了java爬蟲(chóng)的兩種實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • Mybatis動(dòng)態(tài)Sql標(biāo)簽使用小結(jié)

    Mybatis動(dòng)態(tài)Sql標(biāo)簽使用小結(jié)

    本文主要介紹了Mybatis動(dòng)態(tài)Sql標(biāo)簽使用,常用的動(dòng)態(tài)sql標(biāo)簽包括?if、choose(when、otherwise)、trim(where、set)、foreach,下面就來(lái)介紹一下
    2024-04-04
  • Java split()方法中的特殊符號(hào)舉例詳解

    Java split()方法中的特殊符號(hào)舉例詳解

    Java中的split方法可以將一個(gè)字符串按照指定的分隔符進(jìn)行分割,返回一個(gè)字符串?dāng)?shù)組,這篇文章主要給大家介紹了關(guān)于Java split()方法中的特殊符號(hào)的相關(guān)資料,需要的朋友可以參考下
    2023-07-07
  • Java貪心算法之Prime算法原理與實(shí)現(xiàn)方法詳解

    Java貪心算法之Prime算法原理與實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Java貪心算法之Prime算法原理與實(shí)現(xiàn)方法,簡(jiǎn)單描述了Prime算法的概念、原理、實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下
    2017-09-09
  • 如何用java給文件加密的簡(jiǎn)單實(shí)現(xiàn)

    如何用java給文件加密的簡(jiǎn)單實(shí)現(xiàn)

    文件加密,簡(jiǎn)單來(lái)說(shuō)就是把文件讀取出來(lái),把讀取出來(lái)的字節(jié)碼數(shù)組進(jìn)行遍歷,把每一個(gè)碼值和一個(gè)秘鑰(隨便一個(gè)數(shù))進(jìn)行異或運(yùn)算,將運(yùn)算后的結(jié)果全部寫(xiě)入到文件里,這篇文章主要介紹了如何用java給文件加密的簡(jiǎn)單實(shí)現(xiàn),需要的朋友可以參考下
    2023-12-12

最新評(píng)論

莱州市| 萍乡市| 安新县| 金门县| 神木县| 苍梧县| 泸州市| 锦州市| 和硕县| 遂平县| 容城县| 通河县| 虞城县| 黎平县| 恭城| 清徐县| 厦门市| 永善县| 白水县| 固原市| 天等县| 望奎县| 夹江县| 桐城市| 临夏县| 梁山县| 丽水市| 汉阴县| 来凤县| 义马市| 融水| 尼玛县| 乐安县| 秀山| 绥德县| 商洛市| 清新县| 博白县| 新化县| 凤凰县| 霸州市|