MyBatis 动态 SQL 与批量插入优化:从循环单条到一条 SQL 插万行 MyBatis 动态 SQL 与批量插入优化:从循环单条到一条 SQL 插万行用 MyBatis 写查询,条件一多就开始拼字符串,SQL 里全是11这种脏东西;做批量插入时又习惯性 for 循环调 mapper,一万条数据插了半分钟。这两个痛点其实都有干净的解法。这篇把动态 SQL 的四个核心标签讲透,再一步步把批量插入从「每秒几百条」优化到「秒级万行」,代码都能直接跑。动态 SQL:告别where 11先看最原始的拼接写法,很多老项目里到处都是:!-- 反面教材:靠 11 兜底,SQL 脏且易错 --selectidsearchresultTypeUserselect * from user where 11iftestname ! nulland name #{name}/ififteststatus ! nulland status #{status}/if/selectwhere 11是为了解决「第一个条件前面要不要加 and」的问题,但它让 SQL 变脏,还可能让优化器误判。MyBatis 的where标签专门解决这个:它会自动加上 where,并智能去掉紧跟其后的第一个 and/or。selectidsearchresultTypeUserselect * from userwhereiftestname ! null and name ! and name #{name}/ififteststatus ! nulland status #{status}/if/where/select如果所有条件都不成立,where连 where 关键字都不会输出,SQL 依然合法。同理,更新语句用set标签自动处理末尾多余的逗号:updateidupdateupdate usersetiftestname ! nullname #{name},/ififteststatus ! nullstatus #{status},/if/setwhere id #{id}/updateset会自动去掉最后一个字段后面多余的逗号,你只管每行都写逗号就行。foreach:IN 查询与批量的基础foreach用来遍历集合,最常见的是IN查询:selectidfindByIdsresultTypeUserselect * from user where id inforeachcollectionidsitemidopen(separator,close)#{id}/foreach/selectopen/close是首尾包裹,separator是元素分隔符。生成的 SQL 是where id in (?, ?, ?)。坑点一:集合为空会生成in ()语法错误。调用前一定要判空:if(idsnull||ids.isEmpty()){returnCollections.emptyList();// 空集合直接返回,别进 SQL}坑点二:IN 列表别太长。几千个 id 塞进 IN 会让 SQL 巨长、优化器变慢,MySQL 还有max_allowed_packet限制。超过几百个建议分批查。批量插入:从 for 循环到一条 SQL最慢的写法:for 循环单条插入// 反面教材:一万次网络往返,极慢for(Useru:users){userMapper.insert(u);// 每条一次 SQL、一次网络往返}一万条就是一万次数据库往返,每次都有网络和 SQL 解析开销,慢到无法接受。用 foreach 拼成一条 INSERT把多行 values 拼进一条 SQL,一次往返插完:insertidbatchInsertinsert into user (name, status) valuesforeachcollectionusersitemuseparator,(#{u.name}, #{u.status})/foreach/insert对应 mapper 接口:intbatchInsert(Param(users)ListUserusers);生成的 SQL 形如insert into user (name, status) values (?,?),(?,?),(?,?)...。一万条从几十秒降到几百毫秒,这是最立竿见影的一步。但这个方案有上限:拼出来的 SQL 长度受 MySQLmax_allowed_packet(默认 4MB/16MB)限制,几万行、字段又多时会超包报错。所以要分批,每批 500~1000 条:publicvoidbatchInsertInChunks(ListUserusers){intbatchSize1000;for(inti0;iusers.size();ibatchSize){ListUserchunkusers.subList(i,Math.min(ibatchSize,users.size()));userMapper.batchInsert(chunk);// 每批一条 SQL}}数据量极大时:用 ExecutorType.BATCH当数据量到十万级、或者要批量 update/delete 时,更稳的是 MyBatis 的批处理执行器。它复用同一个PreparedStatement,把多次操作攒到一起 flush,底层走 JDBC 的addBatch:publicvoidbatchInsertWithExecutor(ListUserusers,SqlSessionFactoryfactory){// 关键:openSession(ExecutorType.BATCH) 开启批处理模式try(SqlSessionsessionfactory.openSession(ExecutorType.BATCH)){UserMappermappersession.getMapper(UserMapper.class);inti0;for(Useru:users){mapper.insert(u);// 这里仍是单条 insert 语句,但不会立即执行if(i%10000){session.flushStatements();// 每 1000 条 flush 一次,避免攒太多爆内存}}session.flushStatements();// 提交剩余的session.commit();}}它和 foreach 拼 SQL 的区别:foreach 是「一条超长 SQL」,BATCH 是「很多条短 SQL 一次性发送」。BATCH 模式对超大数据量更友好,不受单条 SQL 长度限制,还能统一用于 insert/update/delete。用 MySQL 时还要在连接串加上rewriteBatchedStatementstrue,否则 JDBC 的 addBatch 对 insert 不会真正合并,优化打折:jdbc:mysql://host:3306/db?rewriteBatchedStatementstrue加了这个参数,驱动会把多条 insert 重写成一条多值 insert,批处理才真正生效——这是最容易被忽略、却决定性能的一行。三种方案怎么选几十到几百条:foreach 拼一条 INSERT,简单直接。几千到几万条:foreach 分批(每批 1000),兼顾速度和 packet 限制。十万级以上、或要批量 update:ExecutorType.BATCHrewriteBatchedStatementstrue,最稳。小结动态 SQL 用where替代where 11,用set处理更新的逗号,SQL 干净不易错。foreach做 IN 查询,务必判空集合(避免in ())、控制列表长度。批量插入三级优化:for 单条(最慢)→ foreach 拼一条 SQL(快,但受 packet 限制要分批)→ExecutorType.BATCH(超大数据量最稳)。MySQL 用批处理必须在连接串加rewriteBatchedStatementstrue,否则 addBatch 不合并,白优化。一句话记忆点:别在 Java for 循环里调 insert;小批量 foreach 拼 SQL,大批量 BATCH 执行器加 rewriteBatchedStatements。

相关新闻

最新新闻

UE自动化资源管理:Python脚本实现DataAsset自动收集与更新

UE自动化资源管理:Python脚本实现DataAsset自动收集与更新

1. 项目概述与核心痛点在Unreal Engine(UE)项目中,尤其是那些资源密集型或需要大量配置数据的游戏里,我们经常会遇到一个非常具体且繁琐的问题:如何高效地管理那些散布在项目各个角落的、需要被运行时引用的资源&#…

2026/7/14 17:28:04
基于Rokid灵珠平台的空间陈列师智能体技术解析

基于Rokid灵珠平台的空间陈列师智能体技术解析

1. 项目背景与核心价值在传统家居设计领域,空间规划往往依赖设计师的经验和主观判断。业主提供的户型图和需求描述,经过人工测量、草图绘制、反复修改才能形成最终方案。这个过程通常需要3-5个工作日,沟通成本高且难以量化评估设计合理性。我…

2026/7/14 17:28:04
【ChatGPT课程开发黄金法则】:20年教育科技专家亲授——5大不可绕过的AI教学设计陷阱与避坑指南

【ChatGPT课程开发黄金法则】:20年教育科技专家亲授——5大不可绕过的AI教学设计陷阱与避坑指南

更多请点击: https://intelliparadigm.com 第一章:ChatGPT课程开发的底层逻辑与范式迁移 传统课程开发遵循“目标—内容—评估”线性范式,而ChatGPT驱动的课程设计转向“提示—反馈—迭代”的动态闭环。其底层逻辑根植于大语言模型的三重能力…

2026/7/14 17:28:04
ChatGPT用户手册生成暗黑技巧(内部培训绝密资料):用LLM自动生成+人工校验双流水线,效率提升5倍且通过ISO 27001审计

ChatGPT用户手册生成暗黑技巧(内部培训绝密资料):用LLM自动生成+人工校验双流水线,效率提升5倍且通过ISO 27001审计

更多请点击: https://intelliparadigm.com 第一章:ChatGPT用户手册生成的合规性基线与审计锚点 在企业级AI应用落地过程中,ChatGPT生成的用户手册并非单纯的技术文档输出,而是承载数据安全、内容责任与监管可追溯性的关键合规载…

2026/7/14 17:28:04
Phrase Android库完全指南:终极字符串格式化解决方案

Phrase Android库完全指南:终极字符串格式化解决方案

Phrase Android库完全指南:终极字符串格式化解决方案 【免费下载链接】phrase Phrase is an Android string resource templating library 项目地址: https://gitcode.com/gh_mirrors/ph/phrase Phrase是一款专为Android开发者打造的终极字符串资源模板库&am…

2026/7/14 17:28:04
模板驱动文档自动化:从填空题到文档工厂

模板驱动文档自动化:从填空题到文档工厂

1. 项目概述:用模板把文档生产变成“填空题” 你有没有过这种体验:每周要交三份客户方案,每份结构雷同——封面、目录、痛点分析、解决方案、报价页、服务承诺——但每次都要从零新建Word、手动调格式、复制粘贴旧内容、反复检查页眉页脚是否…

2026/7/14 17:23:04

月新闻