MyBatis批量更新推荐三种安全高效方案:①CASE WHEN单SQL(跨库兼容、防注入);②foreach拼多条UPDATE(仅MySQL支持,需allowMultiQueries=true);③ExecutorType.BATCH手动批处理(性能最优、不依赖数据库)。

用 CASE WHEN 拼接单条 UPDATE(最常用、跨库兼容)
这是最稳妥的方案:只发一条 SQL,利用 CASE WHEN 按主键或唯一键区分不同记录的字段值,天然防注入(所有参数走 #{}),且无需修改数据库连接配置。
关键点:
-
WHERE 条件必须精准覆盖待更新的所有行(如
id IN (...)或组合唯一键),否则可能误更新 - 每个要更新的字段都要单独写一个
CASE分支,foreach遍历一次 list;字段越多,SQL 越长,但仍是单条语句 - MySQL、Oracle、PostgreSQL 均支持,无兼容性风险
示例(按 id 更新 name 和 age):
<update id="updateBatchByCase">
UPDATE t_student
<set>
name = CASE id
<foreach collection="list" item="item">
WHEN #{item.id} THEN #{item.name}
</foreach>
END,
age = CASE id
<foreach collection="list" item="item">
WHEN #{item.id} THEN #{item.age}
</foreach>
END
</set>
WHERE id IN
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item.id}
</foreach>
</update>
用 foreach 拼多条 UPDATE(简单直接,仅限 MySQL)
本质是生成类似 UPDATE ...; UPDATE ...; UPDATE ...; 的语句串,一次提交。性能好,逻辑清晰,但强依赖 MySQL 的 allowMultiQueries=true 配置,其他数据库(如 Oracle、PostgreSQL)不支持,生产环境需谨慎评估。
立即学习“Java免费学习笔记(深入)”;
操作要点:
- 在 JDBC URL 中显式开启:
jdbc:mysql://host:port/db?allowMultiQueries=true - XML 中用
separator=";"拼接,每条 UPDATE 独立完整 - 仍使用
#{}绑定参数,安全无注入
示例:
<update id="updateBatchMulti">
<foreach collection="list" item="item" separator=";">
UPDATE t_student
SET name = #{item.name}, age = #{item.age}
WHERE id = #{item.id}
</foreach>
</update>
用 ExecutorType.BATCH 手动批处理(大批量、高性能首选)
这不是拼 SQL,而是让 MyBatis 底层复用 PreparedStatement,把多条相同结构的 UPDATE 缓存后批量提交。适合万级数据、字段更新逻辑统一的场景,性能最优,且完全不依赖数据库特性。
注意细节:
- 需手动获取
SqlSession并指定ExecutorType.BATCH - 不能混用查询操作(SELECT 会触发 flush)
- 异常时需自行回滚,事务管理更精细
Java 示例片段:
SqlSessionFactory factory = ...;
try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH)) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
for (User user : userList) {
mapper.updateById(user); // 单条 update 方法
}
sqlSession.commit(); // 一次性提交全部
}
不推荐的写法
避免以下做法:
- 拼接字符串 + ${} 取值:极易引发 SQL 注入,尤其当字段名或条件来自用户输入时
-
超长 CASE WHEN(如 500+ 行):MySQL 有
max_allowed_packet限制,可能报错;建议单次批量控制在 200–500 条以内 - 滥用 ON DUPLICATE KEY UPDATE:它本质是 INSERT 语义,仅适用于“存在则更新、不存在则插入”的 upsert 场景,不是纯更新,且仅 MySQL/某些版本 PostgreSQL 支持


















