MyBatisPlus如何優(yōu)化千萬級數(shù)據(jù)的CRUD
背景
做 Java 開發(fā) 8 年,接觸過 Hibernate、JPA、MyBatis,到現(xiàn)在主力框架 MyBatis Plus(簡稱 MP)。一路踩坑無數(shù),從最初寫死 SQL 到現(xiàn)在用 Lambda 鏈?zhǔn)讲僮?,感觸最深的是:CRUD 看似簡單,數(shù)據(jù)量一大,性能問題就來了。
最近負(fù)責(zé)的一個(gè)項(xiàng)目,數(shù)據(jù)庫表量級破千萬,每次執(zhí)行 CRUD 都像走鋼絲,稍有不慎就引起數(shù)據(jù)庫報(bào)警。本文就結(jié)合這個(gè)項(xiàng)目的實(shí)戰(zhàn)經(jīng)驗(yàn),聊聊 MyBatis Plus 在千萬級數(shù)據(jù)場景下如何優(yōu)化 CRUD 操作。
一、MyBatis Plus 簡介
MP 是 MyBatis 的增強(qiáng)工具,主打“無侵入、低門檻、強(qiáng)增強(qiáng)”,提供了一整套優(yōu)雅的 CRUD 封裝,尤其適合中后臺(tái)系統(tǒng)的開發(fā)。
但性能優(yōu)化這件事,MP 提供了鉤子,還得靠我們自己去掌握底層邏輯與場景判斷。
二、千萬級數(shù)據(jù)的挑戰(zhàn)
當(dāng)數(shù)據(jù)達(dá)到千萬級時(shí),常見的問題有:
- 查詢慢、分頁卡頓
- 更新/刪除誤操作影響大
- 數(shù)據(jù)遷移困難
- 索引策略不合理
- 樂觀鎖/悲觀鎖未啟用帶來并發(fā)問題
三、優(yōu)化 CRUD 的關(guān)鍵策略
下面我從 增、刪、改、查 四個(gè)維度,結(jié)合 MP 的用法,逐一拆解優(yōu)化策略。
1. 查詢優(yōu)化(Select)
使用分頁插件 + 索引優(yōu)化
Page<User> page = new Page<>(1, 10); IPage<User> result = userMapper.selectPage(page, new QueryWrapper<User>() .eq("status", "active") .orderByDesc("create_time"));
優(yōu)化點(diǎn):
- 創(chuàng)建復(fù)合索引
(status, create_time)
,避免文件排序 - 設(shè)置合理的
limit
范圍,避開深分頁(推薦游標(biāo)分頁)
游標(biāo)分頁(Keyset Pagination)案例:
QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.lt("id", lastId) .orderByDesc("id") .last("limit 100"); List<User> users = userMapper.selectList(wrapper);
比傳統(tǒng) OFFSET
分頁快得多,適合批量導(dǎo)出或加載。
2. 插入優(yōu)化(Insert)
批量插入代替單條插入
List<User> userList = new ArrayList<>(); for (int i = 0; i < 1000; i++) { userList.add(new User("user" + i)); } userMapper.insertBatchSomeColumn(userList); // 需自定義方法或 MyBatis 擴(kuò)展
建議:
- 單次批量插入控制在 1000 條以內(nèi),避免 SQL 超長
- 使用原生 JDBC 批處理,性能更優(yōu)
3. 更新優(yōu)化(Update)
避免全表更新
錯(cuò)誤:
userMapper.update(null, new UpdateWrapper<User>().set("status", "inactive"));
優(yōu)化:
UpdateWrapper<User> wrapper = new UpdateWrapper<>(); wrapper.eq("status", "active"); wrapper.set("status", "inactive"); userMapper.update(null, wrapper);
永遠(yuǎn)記?。?strong>Update 要加條件!
樂觀鎖控制并發(fā)更新
@TableField(fill = FieldFill.UPDATE) @Version private Integer version;
user.setVersion(3); userMapper.updateById(user); // MP 會(huì)自動(dòng)加 version 判斷
4. 刪除優(yōu)化(Delete)
邏輯刪除替代物理刪除
@TableLogic private Integer isDeleted;
userMapper.deleteById(123L); // 實(shí)際執(zhí)行的是 UPDATE 操作
邏輯刪除的優(yōu)勢:
- 避免誤刪
- 保留數(shù)據(jù)審計(jì)
- 與回收站機(jī)制兼容
注意:邏輯刪除字段要加索引!
四、批處理與異步處理
在千萬級數(shù)據(jù)場景,批處理 + 異步化 是性能優(yōu)化的核心手段:
- 使用
Stream
分批處理大數(shù)據(jù)集合 - 配合 Spring Batch 或自定義線程池實(shí)現(xiàn)異步任務(wù)
- 使用定時(shí)任務(wù)(如 XXL-JOB)分時(shí)段處理數(shù)據(jù)
五、數(shù)據(jù)庫層面的優(yōu)化建議
- 合理建索引(避免過多/重復(fù)索引)
- 垂直/水平分表(ShardingSphere、MyCat)
- 使用中間件緩存熱點(diǎn)數(shù)據(jù)(Redis)
- 慎用視圖和子查詢,優(yōu)先考慮 JOIN 重構(gòu)
六、總結(jié):CRUD 優(yōu)化是一場系統(tǒng)工程
MyBatis Plus 提供了優(yōu)雅的接口,但數(shù)據(jù)量上來之后,框架只是工具,根本還在底層 SQL 和設(shè)計(jì)策略上。
作為一個(gè)寫了 8 年 Java 的程序員,我最大的體會(huì)是:
性能不是調(diào)出來的,是設(shè)計(jì)出來的。
合理建模 + 規(guī)范使用 MP + 數(shù)據(jù)庫調(diào)優(yōu),才能讓你的系統(tǒng)在千萬級數(shù)據(jù)面前從容應(yīng)對。
到此這篇關(guān)于MyBatisPlus如何優(yōu)化千萬級數(shù)據(jù)的CRUD的文章就介紹到這了,更多相關(guān)MyBatisPlus優(yōu)化數(shù)據(jù)CRUD內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springmvc中進(jìn)行數(shù)據(jù)保存以及日期參數(shù)的保存過程解析
這篇文章主要介紹了springmvc中進(jìn)行數(shù)據(jù)保存以及日期參數(shù)的保存過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09SpringBoot實(shí)現(xiàn)國際化過程詳解
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)國際化過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12IDEA連接MySQL提示serverTimezone的問題及解決方法
很多朋友私聊小編,使用IDEA軟件連接MySQL數(shù)據(jù)庫時(shí)總是提示Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.的錯(cuò)誤,小編就不一一回復(fù)大家了,下面小編把我的解決方法分享到腳本之家平臺(tái),需要的朋友參考下吧2021-05-05如何使用IntelliJ?IDEA進(jìn)行Java內(nèi)存分析詳解
這篇文章主要介紹了如何使用IntelliJ?IDEA進(jìn)行Java內(nèi)存分析的相關(guān)資料,包括內(nèi)存消耗情況的查看、內(nèi)存泄漏的分析、垃圾回收情況的優(yōu)化等,通過IntelliJIDEA提供的工具,開發(fā)者可以有效地提升應(yīng)用程序的性能和穩(wěn)定性,需要的朋友可以參考下2025-05-05Spring Boot整合Spring Data JPA過程解析
這篇文章主要介紹了Spring Boot整合Spring Data JPA過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10