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

SpringBoot中六種批量更新Mysql的方式效率對比分析

 更新時間:2025年07月15日 16:03:14   作者:九轉(zhuǎn)成圣  
文章比較了MySQL大數(shù)據(jù)量批量更新的多種方法,指出REPLACE INTO和ON DUPLICATE KEY效率最高但存在數(shù)據(jù)風(fēng)險,MyBatis-Plus分批更新較優(yōu),CASE WHEN因循環(huán)多效率較低,建議根據(jù)項目限制選擇合適方案并分批處理以避免SQL阻塞

先上結(jié)論吧,有空可以自測一下,數(shù)據(jù)量大時運行一次還時挺耗時的

效率比較

小數(shù)據(jù)量時6中批量更新效率不太明顯,根據(jù)項目選擇合適的即可,以1萬條為準(zhǔn)做個效率比較,效率從高到低一次排名如下

  1. replace intoON DUPLICATE KEY效率最高
  2. mybatis-plus 有取巧嫌疑,因為是分批批量更新,其他幾種都是一次更新
  3. for循環(huán)憑借sql和JdbcTemplate相近,即使5萬條,10萬條效率也相近
  4. case when

然而有時候我們只能選擇case when,因為replace intoON DUPLICATE KEY公司不一定讓用,項目也不一定引入mybatis-plus,數(shù)據(jù)庫url中也不一定有allowMultiQueries=true參數(shù),算是一個兜底方案吧,不管用那種方式大數(shù)據(jù)量時都需要考慮分批

測試結(jié)構(gòu)

環(huán)境信息:mysql-8.0.35-winx64,本地win 10

依次為測試次數(shù)-平均耗時-最小耗時-最大耗時,單位為毫秒

數(shù)據(jù)量forcase whenreplace intoON DUPLICATE KEYmybatis-plusJdbcTemplate
500100-61-41-1202100-66-57-426100-16-10-282100-15-10-293100-73-52-564100-87-59-1449
1000100-131-94-2018100-241-219-675100-28-18-376100-25-17-331100-117-98-599100-188-136-2397
5000100-852-735-8297100-11219-10365-13496100-95-83-569100-93-82-552100-618-517-1415100-1161-911-9334
1000010-3957-2370-1730410-45537-44465-48119100-191-171-762100-188-169-772100-1309-1085-5021100-3671-2563-31112
5000010-50106-34568-130651卡死不動100-1026-919-1868100-1062-945-1934100-8062-6711-20841100-48744-35482-191011
10000010-160170-106223-264434卡死不動10-2551-2292-368810-2503-2173-3579100-17205-14436-2488110-169771-110522-343278

心得:

sql語句for循環(huán)效率其實相當(dāng)高的,因為它僅僅有一個循環(huán)體,只不過最后update語句比較多,量大了就有可能造成sql阻塞,同時在mysql的url上需要加上allowMultiQueries=true參數(shù),即 jdbc:mysql://localhost:3306/mysqlTest?characterEncoding=utf-8&allowMultiQueries=true(公司項目不一定加,我們也不一定有權(quán)限加)。

case when雖然最后只會有一條更新語句,但是xml中的循環(huán)體有點多,每一個case when 都要循環(huán)一遍list集合,所以大批量拼sql的時候會比較慢,所以效率問題嚴(yán)重。使用的時候建議分批插入(我們公司一直用的就是這種,但是必須分批)。

duplicate key update可以看出來是最快的,但是公司一般都禁止使用replace into和INSERT INTO … ON DUPLICATE KEY UPDATE,這種sql有可能會造成數(shù)據(jù)丟失和主從上表的自增id值不一致。而且用這個更新時,記得一定要加上id,而且values()括號里面放的是數(shù)據(jù)庫字段,不是java對象的屬性字段

根據(jù)效率,安全方面綜合考慮,選擇適合的很重要。

數(shù)據(jù)庫

CREATE TABLE `people` (
  `id` bigint(8) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(50) NOT NULL DEFAULT '',
  `last_name` varchar(50) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

初始化測試數(shù)據(jù)

//初始化10w數(shù)據(jù)
@Test
void init10wData() {
    for (int i = 0; i < 100000; i++) {
        People people = new People();
        people.setFirstName(UUID.randomUUID().toString());
        people.setLastName(UUID.randomUUID().toString());
        peopleDAO.insert(people);
    }
}

批量修改方案

第一種 for

<!-- 批量更新第一種方法,通過接收傳進(jìn)來的參數(shù)list進(jìn)行循環(huán)組裝sql -->
<update id="updateBatch" parameterType="java.util.List">
    <foreach collection="list" item="item" index="index" open="" close="" separator=";">
        update people
        <set>
            <if test="item.firstName != null">
                first_name = #{item.firstName,jdbcType=VARCHAR},
            </if>
            <if test="item.lastName != null">
                last_name = #{item.lastName,jdbcType=VARCHAR},
            </if>
        </set>
        where id = #{item.id,jdbcType=BIGINT}
    </foreach>
</update>

第二種 case when

<!-- 批量更新第二種方法,通過 case when語句變相的進(jìn)行批量更新 -->
<update id="updateBatch2" parameterType="java.util.List">
    update people
    <set>
        <foreach collection="list" item="item">
            <if test="item.firstName != null">
                first_name = case when id = #{item.id} then #{item.firstName} else first_name end,
            </if>
            <if test="item.lastName != null">
                last_name = case when id = #{item.id} then #{item.lastName} else last_name end,
            </if>
        </foreach>
    </set>
    where id in
    <foreach collection="list" item="item" separator="," open="(" close=")">
        #{item.id}
    </foreach>
</update>

第三種 replace into

<!-- 批量更新第三種方法,通過 replace into  -->
<update id="updateBatch3" parameterType="java.util.List">
    replace into people
    (id,first_name,last_name) values
    <foreach collection="list" index="index" item="item" separator=",">
        (#{item.id},
        #{item.firstName},
        #{item.lastName})
    </foreach>
</update>

第四種 ON DUPLICATE KEY UPDATE

<!-- 批量更新第四種方法,通過 duplicate key update  -->
<update id="updateBatch4" parameterType="java.util.List">
    insert into people
    (id,first_name,last_name) values
    <foreach collection="list" index="index" item="item" separator=",">
        (#{item.id},
        #{item.firstName},
        #{item.lastName})
    </foreach>
    ON DUPLICATE KEY UPDATE
    id=values(id),first_name=values(first_name),last_name=values(last_name)
</update>

第五種mybatis-plus提供的的批量更新

default boolean updateBatchById(Collection<T> entityList) {
    return this.updateBatchById(entityList, 1000);
}
boolean updateBatchById(Collection<T> entityList, int batchSize);

mybatis-plus提供的批量更新是分批批量更新,默認(rèn)每批1000條,可以指定分批的條數(shù),每批執(zhí)行完成后提交一下事務(wù),不加@Transactional可能會出現(xiàn)第一批更新成功了,第二批更新失敗了的情況.

第六種JdbcTemplate提供的批量更新

測試代碼

/**
 * PeopleDAO繼承基類
 */
@Mapper
@Repository
public interface PeopleDAO extends MyBatisBaseDao<People, Long> {

    void updateBatch(@Param("list") List<People> list);

    void updateBatch2(List<People> list);

    void updateBatch3(List<People> list);

    void updateBatch4(List<People> list);
}

@SpringBootTest
class PeopleMapperTest {
    @Resource
    PeopleMapper peopleMapper;
    @Resource
    PeopleService peopleService;
    @Resource
    JdbcTemplate jdbcTemplate;

    @Test
    void init10wData() {
        for (int i = 0; i < 100000; i++) {
            People people = new People();
            people.setFirstName(UUID.randomUUID().toString());
            people.setLastName(UUID.randomUUID().toString());
            peopleMapper.insert(people);
        }
    }


    @Test
    void updateBatch() {
        List<People> list = new ArrayList();
        int loop = 100;
        int count = 5000;
        Long maxCost = 0L;//最長耗時
        Long minCost = Long.valueOf(Integer.MAX_VALUE);//最短耗時
        for (int j = 0; j < count; j++) {
            People people = new People();
            people.setId(ThreadLocalRandom.current().nextInt(0, 100000));
            people.setFirstName(UUID.randomUUID().toString());
            people.setLastName(UUID.randomUUID().toString());
            list.add(people);
        }

        Long startTime = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
            Long curStartTime = System.currentTimeMillis();
            // peopleMapper.updateBatch4(list);
            // peopleService.updateBatchById(list);
            jdbcTemplateBatchUpdate(list);
            Long curCostTime = System.currentTimeMillis() - curStartTime;
            if (maxCost < curCostTime) {
                maxCost = curCostTime;
            }
            if (minCost > curCostTime) {
                minCost = curCostTime;
            }
        }
        System.out.println(loop + "-" + (System.currentTimeMillis() - startTime) / loop + "-" + minCost + "-" + maxCost );
    }

    private void jdbcTemplateBatchUpdate (List<People> list){
        String sql = "update people set first_name=?,last_name=? where id = ?";
        List<Object[]> params = list.stream().map(item -> new Object[]{item.getFirstName(), item.getLastName(), item.getId()}).collect(Collectors.toList());
        jdbcTemplate.batchUpdate(sql,params);
    }
}

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java中的本地緩存GuavaCache使用方法和示例教程

    java中的本地緩存GuavaCache使用方法和示例教程

    GuavaCache是Google提供的高效本地緩存工具,支持線程安全、自動加載、過期策略及內(nèi)存回收,適用于高并發(fā)場景,可提升系統(tǒng)性能,減少數(shù)據(jù)庫訪問壓力
    2025-07-07
  • 深入淺析TomCat Session管理分析

    深入淺析TomCat Session管理分析

    這篇文章主要介紹了深入淺析TomCat Session管理分析,需要的朋友可以參考下
    2015-11-11
  • idea以文本形式輸出idea目錄結(jié)構(gòu)方式

    idea以文本形式輸出idea目錄結(jié)構(gòu)方式

    本文介紹了使用Alt+F12打開Terminal終端,cd到項目路徑下,使用tree命令查看項目結(jié)構(gòu)的方法,并表示這是個人經(jīng)驗,僅供參考
    2026-05-05
  • SpringBoot結(jié)合prometheus自定義埋點方式

    SpringBoot結(jié)合prometheus自定義埋點方式

    文章介紹了如何使用Spring Actuator、Prometheus和Grafana進(jìn)行度量統(tǒng)計收集、數(shù)據(jù)收集和數(shù)據(jù)展示,以監(jiān)控生成環(huán)境機(jī)器的性能指標(biāo)和業(yè)務(wù)數(shù)據(jù)指標(biāo)
    2024-12-12
  • Java接入支付寶授權(quán)第三方登錄的完整步驟

    Java接入支付寶授權(quán)第三方登錄的完整步驟

    不管是支付寶支付,還是微信支付,還是銀聯(lián)支付等,大部分的支付流程都是相似的,這篇文章主要給大家介紹了關(guān)于Java接入支付寶授權(quán)第三方登錄的相關(guān)資料,使用支付寶的沙盒環(huán)境示例,需要的朋友可以參考下
    2021-07-07
  • Java過濾器如何解決存儲型xss攻擊問題

    Java過濾器如何解決存儲型xss攻擊問題

    這篇文章主要介紹了Java過濾器如何解決存儲型xss攻擊問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • java使用SFTP上傳文件到資源服務(wù)器

    java使用SFTP上傳文件到資源服務(wù)器

    這篇文章主要介紹了java使用SFTP上傳文件到資源服務(wù)器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Java8中CompletableFuture使用場景與實現(xiàn)原理

    Java8中CompletableFuture使用場景與實現(xiàn)原理

    CompletableFuture是java8引入的新類,該類實現(xiàn)了Future接口和 CompletionStage接口,封裝了future、forkjoin相關(guān)類來執(zhí)行異步,這篇文章主要給大家介紹了關(guān)于Java8中CompletableFuture使用場景與實現(xiàn)原理的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • 淺談Java轉(zhuǎn)義符\\|

    淺談Java轉(zhuǎn)義符\\|

    java中\(zhòng)需要用\\來表示吧這個你應(yīng)該知道,而split中傳入的參數(shù)是什么呢 他并不是普通的字符串 你可以查一下api文檔 它要求傳入的是正則表達(dá)式 而正則表達(dá)式也需要這個\所以在這里有這個\\
    2015-06-06
  • 通過Java設(shè)置Word頁面背景色過程詳解

    通過Java設(shè)置Word頁面背景色過程詳解

    這篇文章主要介紹了通過Java設(shè)置Word頁面背景色過程詳解,Word中可以針對不同文檔排版設(shè)計要求來設(shè)置背景設(shè)置顏色。常見的可設(shè)置單一顏色、漸變色或加載圖片來設(shè)置成背景。下面通過Java來設(shè)置以上3種Word頁面背景色,需要的朋友可以參考下
    2019-07-07

最新評論

甘孜县| 大名县| 孝昌县| 庄河市| 忻州市| 台州市| 会昌县| 乐昌市| 辽阳县| 南京市| 兴宁市| 乌兰察布市| 手机| 昆山市| 寿阳县| 临夏市| 巨野县| 松原市| 五指山市| 厦门市| 思茅市| 和龙市| 忻州市| 石门县| 北安市| 乐平市| 荔波县| 南阳市| 大同市| 尖扎县| 瑞丽市| 江城| 武平县| 阿图什市| 沂水县| 尤溪县| 南雄市| 海丰县| 德阳市| 延安市| 栾城县|