哈喽大家好,我是你们熟悉的31岁技术博主小米,一个爱写bug也爱修bug的程序员。
最近啊,我们团队在准备招一个资深Java后端的时候,我和同事们一起参与了几轮面试。说实话,现在的社招简历个个都“光鲜亮丽”,但真刀真枪问问题时,还是能看出谁是“纸老虎”,谁是真“硬核”。
今天就想和大家聊聊,在其中一场技术面试中,我们问到的一个很常见但也很容易答偏的问题:
“MyBatis如何执行批量操作?”
结果,10个人里有8个说的是用 foreach 实现多条 insert,还有人说:“我直接循环 insert 不就好了?”听得我差点从椅子上摔下来……
好了,话不多说,我们这就来还原下这个问题背后的故事,顺便也讲讲批量操作在实际业务中是怎么踩坑的。
故事开头:10W条数据插入,系统差点崩了
那是两年前的一个深夜,我和搭档阿强在处理一个“临时需求”——对接一个供应商的订单系统,导入对方历史订单数据到我们的数据库中,一共 10万条。
阿强一开始用的是传统方式:

起初没啥问题,可当他按下执行键不到5分钟,数据库 CPU 就飙到了95%,慢查询一堆,Tomcat还直接卡了两次。我们都懵了。
我: “哥们儿,你是循环调用 insert 啊?MyBatis 不支持批量的吗?”
阿强: “我也以为它自动会合并SQL来执行呢……”
好吧,阿强对不起,这锅我不能替你背。那天,我第一次系统地去翻了 MyBatis 的批量处理机制,才发现里面水还挺深!
误区澄清:MyBatis不是自动批量执行的!
很多人以为:
“我用 for 循环调用 mapper 的 insert(),MyBatis 会聪明地合并成批量 SQL。”
实际上并不会!
默认情况下,每一次调用 insert(),MyBatis 都会走一次完整的 SQL 执行流程:
- 创建 PreparedStatement
- 设置参数
- 执行 SQL
- 提交事务
一次一条,效率感人。
所以,MyBatis 里如果不做特别处理,循环插入就是 N 次独立 SQL 操作,性能极低。
那怎么才能实现真正的批量呢?继续往下看。
解法一:最常见的 foreach 拼 SQL
我们先来看第一个“半自动化”的方式,也是很多面试者第一反应:用 <foreach> 标签拼接批量 SQL。
XML 中的写法:

这样,MyBatis 就会在一个 SQL 中拼接多组 values(),最后生成一个长 SQL,交由数据库一次性插入。
优点:
- 简单直观,写起来快
- 不依赖底层数据库或MyBatis配置
缺点:
- SQL长度容易超限(数据库对单条SQL长度有限制)
- MySQL 有的版本对 values() 个数也有限制(比如1000)
- 批量更新不好支持
这个方案在 数据量中等(几百~几千) 的时候非常实用,也是我在项目中最常推荐的方式之一。
解法二:使用 SqlSession 的 ExecutorType.BATCH 模式
当你批量的数据量更大,比如 几万条甚至几十万条,怎么办?
这时候推荐你使用更“底层”的方式:显式创建 batch 模式的 SqlSession。
示例代码如下:

优点:
- 真正意义上的批处理操作,性能提升明显
- 控制更细粒度,适用于超大批次导入
缺点:
- 代码稍显复杂
- 不适合和 Spring 的声明式事务混用(除非集成MyBatis-Spring的BatchSession支持)
- 异常处理要注意回滚
这是我们当时救命用的方案,后来 10W 条数据分批导入,耗时从十几分钟缩短到几十秒,系统再也没挂过。
解法三:MyBatis Plus 的批量方法
如果你项目中用的是 MyBatis Plus,那就更简单了。

MyBatis Plus 底层其实也是用了 <foreach> 或 Batch Executor 模式,只不过它帮你封装好了,默认是 1000 条一个批次。
想调整批次大小?

MyBatis Plus 可以说是“懒人专用”,写起来很爽,唯一的问题是你得接受它对 entity 的要求,比如继承 BaseMapper、使用注解等。
关于批量更新与删除
很多同学还会问:
“那批量更新怎么办?”
批量更新就没插入那么简单了,因为更新通常每一条的内容都不一样,SQL 不好拼。
最常见的写法是:
- 使用 <foreach> 迭代 update
- 或者写 CASE WHEN 的 SQL,复杂但效率高
- 真正对性能要求特别高的,还可以考虑存储过程
示例(简单版):

但注意:大部分数据库并不支持多条 SQL 用分号连接执行!你需要配置 MyBatis 支持执行多语句,或用脚本方式执行。
小米碎碎念 & 面试建议
聊了这么多,回到面试场景,小米想说两点:
- MyBatis 的批量操作,面试官考的是你对原理的掌握和实际项目的理解能力。别停留在 API 层面,要能讲出性能问题的原因和应对策略。
- 批量操作从来不是“for循环 insert”这么简单,要考虑 SQL 语句构建、事务处理、缓存清理等多个因素。
真正的资深工程师,看到问题不慌,能根据场景选方案,才是加分项。
结语
好了,今天的技术故事分享到这,MyBatis 批量操作虽然是“老生常谈”,但却是项目中最容易踩坑的一块。写得简单,跑得慢;写得复杂,跑得快——这就是批处理的“魔法”。
如果你正在准备社招,不妨把今天这几个方案都撸一遍,别等到面试的时候说“我回去查查文档”哦~
我是小米,一个正在 debug 也正在成长的技术人,我们下期继续聊聊那些年我们踩过的 Java 社招坑吧!
END
如果你觉得有用,记得点个 在看 + 收藏 + 转发,让更多小伙伴不再掉坑!
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
我们技术人,也要彼此照亮!

被折叠的 条评论
为什么被折叠?



