MyBatis-Plus 批量操作与 rewriteBatchedStatements 优化
目录① 导读卡片② 背景与目标为什么学学完能怎样③ 核心概念与原理3.1 saveBatch 的两种来源3.2 默认行为循环单条 INSERT3.3 真正的一条多值 INSERT④ 逻辑图谱与对比4.1 四种批量插入方案对比⑤ 核心详解5.1 方案一开启 rewriteBatchedStatements推荐5.2 方案二手写 XML 批量 INSERT灵活场景5.3 方案三for 单条 insert反面教材⑥ 典型应用案例6.1 案例巡检 7 条明细的批量插入⑦ 常见坑与最佳实践7.1 易错点清单7.2 面试话术7.3 最佳实践⑧ 总结与学习路线图核心要点自检清单下一步学习① 导读卡片一句话读懂MyBatis-Plus 的saveBatch默认不是一条多值 INSERT而是循环单条 INSERT开启rewriteBatchedStatements后才能合并为一条 SQL大幅降低网络往返 适合人群Java 后端开发者、MyBatis-Plus 使用者、性能优化关注者 难度等级★★★☆☆中等 ⏱阅读时长约 10 分钟 前置知识Spring Boot MyBatis-Plus 基础、JDBC 基本概念② 背景与目标为什么学大多数人用saveBatch时以为它是这样执行的INSERT INTO table (col1, col2) VALUES (v1, v2), (v3, v4), (v5, v6);但实际上默认是这样执行的INSERT INTO table (col1, col2) VALUES (v1, v2); INSERT INTO table (col1, col2) VALUES (v3, v4); INSERT INTO table (col1, col2) VALUES (v5, v6);7 条数据就发 7 次网络往返。这个误解可能导致线上性能瓶颈。学完能怎样理解saveBatch底层的真正执行方式掌握三种批量 INSERT 方案及其性能差异知道rewriteBatchedStatements的作用和用法面试时能讲清楚批量插入怎么优化的③ 核心概念与原理3.1 saveBatch 的两种来源// 方式一IService 自带 public interface InspectionDetailService extends IServiceInspectionDetail {} inspectionDetailService.saveBatch(details); ​ // 方式二ISqlRunner ISqlRunner runner SqlRunnerFactory.getRunner(detailMapper); runner.saveBatch(details);两者底层行为完全一致。3.2 默认行为循环单条 INSERTsaveBatch的默认实现简化源码public boolean saveBatch(CollectionT entityList, int batchSize) { int i 0; String sql INSERT INTO table (...) VALUES (?); // 单条 INSERT 模板 for (T entity : entityList) { executeBatch(sql, entity); // 每条数据单独发一次 i; if (i % batchSize 0) { flushStatements(); // 每 batchSize 条提交一次 } } return true; }默认batchSize 1000虽然叫批量提交但 MySQL 层面每批仍然是多条单行 INSERT只是将多次commit合并为一次3.3 真正的一条多值 INSERTINSERT INTO table (col1, col2) VALUES (v1, v2), (v3, v4), (v5, v6);一次网络往返完成所有数据插入。对比上面默认行为方式7 条数据的网络往返MySQL 层面saveBatch默认7 次7 条单行 INSERT真正的多值 INSERT1 次1 条多值 INSERT④ 逻辑图谱与对比4.1 四种批量插入方案对比批量插入方案 ├─ for insert() → ❌ 7 次网络往返最差 ├─ saveBatch() 默认 → 7 次批量提交仍为单行 INSERT ├─ saveBatch() rewriteBatchedStatements → ✅ 1 条多值 INSERT最推荐 └─ 手写 foreach XML → ✅ 1 条多值 INSERT最灵活方式MySQL 层面网络往返代码量推荐程度for insert()7 条 INSERT7 次少❌ 最差saveBatch()默认7 条 INSERT同事务提交7 次极少⚠️ 一般saveBatch() rewriteBatchedStatements1 条多值 INSERT1 次极少仅加个参数✅首选手写foreach XML1 条多值 INSERT1 次多需写 XML✅ 灵活场景⑤ 核心详解5.1 方案一开启 rewriteBatchedStatements推荐原理MySQL JDBC 驱动提供的参数开启后会自动将 JDBC batch 提交的多个单行 INSERT 合并为一条多值 INSERT。配置方式spring: datasource: druid: url: jdbc:mysql://localhost:3306/mes_db?rewriteBatchedStatementstrue driver-class-name: com.mysql.cj.jdbc.Driver效果验证开启前后对比-- 开启前3 次 INSERT INSERT INTO inspection_detail (...) VALUES (?); INSERT INTO inspection_detail (...) VALUES (?); INSERT INTO inspection_detail (...) VALUES (?); ​ -- 开启后1 次 INSERT3 个值 INSERT INTO inspection_detail (...) VALUES (?), (?), (?);使用代码Service RequiredArgsConstructor public class InspectionSubmitService { private final InspectionDetailService detailService; public void submitInspection() { ListInspectionDetail details dto.getDetails(); // 7 条 detailService.saveBatch(details, 100); // batchSize100 // 开启 rewriteBatchedStatements 后自动合并为一条多值 INSERT } }5.2 方案二手写 XML 批量 INSERT灵活场景当需要自定义 SQL 逻辑如ON DUPLICATE KEY UPDATE、INSERT IGNORE时手动操作更可控insert idbatchInsert parameterTypejava.util.List INSERT INTO inspection_detail (task_id, item_code, number_value, enum_value, photo_url) VALUES foreach collectionlist itemitem separator, (#{item.taskId}, #{item.itemCode}, #{item.numberValue}, #{item.enumValue}, #{item.photoUrl}) /foreach /insert Mapper public interface InspectionDetailMapper { void batchInsert(Param(list) ListInspectionDetail details); } // 调用 inspectionDetailMapper.batchInsert(details); // 一条 SQL 完成5.3 方案三for 单条 insert反面教材// ❌ 不要这样做 for (InspectionDetail detail : details) { detailMapper.insert(detail); }每条数据一次网络往返、一次事务提交。7 条数据 7 次数据库交互。⑥ 典型应用案例6.1 案例巡检 7 条明细的批量插入 需求描述一次巡检提交需插入 7 条巡检明细。要求性能最优且容易维护。 推荐写法# application.yml — 仅需加一个参数 spring: datasource: druid: url: jdbc:mysql://localhost:3306/mes_db?rewriteBatchedStatementstrue driver-class-name: com.mysql.cj.jdbc.Driver Service RequiredArgsConstructor public class InspectionSubmitService { private final InspectionDetailService detailService; Transactional(rollbackFor Exception.class) public void submitInspection(InspectionSubmitDTO dto) { // ... 校验逻辑 ... // saveBatch rewriteBatchedStatements 一条多值 INSERT detailService.saveBatch(dto.toInspectionDetails(), 100); // 更新任务状态 // ... } } 性能对比300 并发压测方案平均响应超时率网络往返for insert()3 秒40%7 次saveBatch()默认2.5 秒30%7 次同事务提交saveBatch() rewriteBatchedStatements500ms1%1 次⑦ 常见坑与最佳实践7.1 易错点清单#坑点现象原因✅ 避坑方案1rewriteBatchedStatements只对 INSERT 有效UPDATE 没合并这是 MySQL JDBC 驱动的设计只关心的 INSERT 场景即可2一次批量数据量过大报错max_allowed_packet限制单条 SQL 太长超出 MySQL 限制调小 batchSize 或调大max_allowed_packet3开了参数但没效果抓日志仍看到多行 INSERT使用的不是 JDBCexecuteBatch()saveBatch 底层恰好就是 JDBC batch4不加参数直接用 saveBatch以为一条 SQL实际多条对 saveBatch 的误解开 rewriteBatchedStatements 或手写 XML7.2 面试话术Q你们的批量插入怎么做的用 MyBatis-Plus 的saveBatch并在 JDBC URL 上加了rewriteBatchedStatementstrue。这样 saveBatch 底层会把多次单行 INSERT 合并为一条多值 INSERT7 条数据的网络往返从 7 次降到 1 次。这个参数是 MySQL JDBC 驱动提供的只需要加个连接参数不用改任何代码。Q为什么不直接手写 XML 的 foreach 批量 INSERT因为 saveBatch rewriteBatchedStatements 已经能达到同样的效果代码量更少、维护更方便。如果以后需要自定义 SQL比如ON DUPLICATE KEY UPDATE再考虑手写 XML。目前简单批量插入场景加个参数就够了。QrewriteBatchedStatements 有什么副作用基本没有。它只影响 INSERT 语句的拼装方式不影响其他操作。唯一要注意的是如果一次插入几万条数据可能超过 MySQL 的max_allowed_packet限制需要调大这个参数。但我们业务场景一次最多 7 条完全没问题。QsaveBatch 的 batchSize 设多少合适设 100 比较合理。如果一次插入数据超过 100 条MyBatis-Plus 会分批执行每 100 条 flush 一次。我们一次最多 7 条100 绰绰有余。如果场景是几千上万的批量导入可以适当调大 batchSize。7.3 最佳实践✅首选方案saveBatchrewriteBatchedStatementstrue零代码改动效果好✅手写 XML当需要自定义逻辑ON DUPLICATE KEY UPDATE、INSERT IGNORE、多表关联插入时使用✅控制批量大小单条 SQL 建议控制在 1000 个以内不超过 1MB避免max_allowed_packet限制❌避免 for 循环 insert除非只有 1~2 条数据否则这是最差的写法⑧ 总结与学习路线图核心要点维度要点一句话记住默认行为saveBatch 是循环单行 INSERT不是多值 INSERT是批量提交优化方案rewriteBatchedStatementstrue加一个参数效果天差地别备选方案手写 foreach XML灵活但有代码量常见坑误以为 saveBatch 就是多值 INSERT先搞清默认行为再优化自检清单我能说清楚 saveBatch 默认是循环单行 INSERT 还是多值 INSERT我知道 rewriteBatchedStatements 是干什么的、怎么配我能对比四种批量插入方案的性能差异我知道什么场景用手写 XML 更合适下一步学习阶段一基础saveBatch 使用 rewriteBatchedStatements 配置 → 完成本文 阶段二进阶MySQL 执行计划分析、批量插入的 InnoDB 锁机制 阶段三源码MyBatis-Plus 批量执行器 SqlBatch 源码、MySQL JDBC Statement.executeBatch() 源码

相关新闻

什么是开放平台

什么是开放平台

也许对于程序员来说,有一个概念一定不陌生,Open API,对,就是开放的应用程序接口。那么开放平台呢?我们不要把他想的那么神秘,简单来说就是Open API Platform,那么什么是Platform,简…

2026/7/5 3:56:36阅读更多 →
新手做抖店副业必学,密文下单 + 先采后付软件,微信小店无货源一件代发工具全套落地方法

新手做抖店副业必学,密文下单 + 先采后付软件,微信小店无货源一件代发工具全套落地方法

抖店密文下单先采购后付款全攻略,新手副业创业零垫资合规开店指南当下很多零基础小白想靠电商做副业、轻创业,首选无货源一件代发模式,不用囤货、不用仓储,但绝大多数新手都会踩两大致命坑:一是手动复制买家地址下单&a…

2026/7/5 3:51:36阅读更多 →
Typora插件完全手册:彻底提升你的Markdown编辑效率终极指南

Typora插件完全手册:彻底提升你的Markdown编辑效率终极指南

Typora插件完全手册:彻底提升你的Markdown编辑效率终极指南 【免费下载链接】typora_plugin Typora Plugin. Feature Enhancement Tool | Typora 插件,功能增强工具 项目地址: https://gitcode.com/gh_mirrors/ty/typora_plugin Typora插件是一个…

2026/7/5 3:51:36阅读更多 →
RPA测试自动化:基于Vagrant与pytest的环境一致性解决方案

RPA测试自动化:基于Vagrant与pytest的环境一致性解决方案

1. 项目概述:当RPA遇上测试自动化如果你正在用Python做RPA(机器人流程自动化),并且同时负责测试工作,那你大概率会遇到一个头疼的问题:如何稳定、高效地测试这些自动化流程本身?RPA脚本往往高度…

2026/7/5 5:11:40阅读更多 →
如何在144Hz显示器上实现电影级流畅播放?MPV高帧率优化完全指南

如何在144Hz显示器上实现电影级流畅播放?MPV高帧率优化完全指南

如何在144Hz显示器上实现电影级流畅播放?MPV高帧率优化完全指南 【免费下载链接】mpv_PlayKit 🔄 mpv player 播放器折腾记录 Windows conf | 中文注释配置 汉化文档 快速帮助入门 | mpv-lazy 懒人包 Win11 x64 config | 着色器 shader 滤镜 filter 整合…

2026/7/5 5:11:40阅读更多 →
百度文库文档打印解决方案:开源JavaScript脚本实现纯净PDF导出

百度文库文档打印解决方案:开源JavaScript脚本实现纯净PDF导出

百度文库文档打印解决方案:开源JavaScript脚本实现纯净PDF导出 【免费下载链接】baidu-wenku fetch the document for free 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wenku 在学术研究和日常工作中,百度文库作为中文文档资源的重要平台…

2026/7/5 5:11:40阅读更多 →
STL到STEP格式转换深度解析:stltostp完全攻略

STL到STEP格式转换深度解析:stltostp完全攻略

STL到STEP格式转换深度解析:stltostp完全攻略 【免费下载链接】stltostp Convert stl files to STEP brep files 项目地址: https://gitcode.com/gh_mirrors/st/stltostp 在数字化设计和制造领域,STL到STEP格式转换是连接快速原型与精密工程的关键…

2026/7/5 5:11:40阅读更多 →
Plone 5升级实战:从Zope 2到Python 3的内容管理重构

Plone 5升级实战:从Zope 2到Python 3的内容管理重构

1. 这不是一次普通升级:Plone 5到底解决了哪些真实痛点?“8 Reasons to Upgrade to Plone 5”这个标题乍看像一份标准的厂商宣传稿,但如果你在2014–2019年间实际维护过Plone 4.x站点——尤其是那些承载着政府信息公开、高校教务系统、科研项…

2026/7/5 5:11:40阅读更多 →
5分钟掌握SRWE:游戏窗口分辨率自由调整的终极指南

5分钟掌握SRWE:游戏窗口分辨率自由调整的终极指南

5分钟掌握SRWE:游戏窗口分辨率自由调整的终极指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的烦恼?想截取一张完美的游戏画面,却发现游戏分辨率限制让…

2026/7/5 5:06:40阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/5 0:01:08阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/5 0:01:08阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/5 0:01:08阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/5 1:30:27阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/5 3:48:10阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/5 3:48:09阅读更多 →