MyBatis MySQL批量更新生效需同时满足:URL加rewriteBatchedStatements=true、MyBatis配置BATCH执行器;XML中推荐CASE WHEN单语句方式,并分批控制在500–2000条以内。

MyBatis 在 MySQL 中做批量更新时,仅靠 XML 里写 <foreach> 或调用 MyBatis-Plus 的 updateBatch 是不够的。真正起效的关键一步:必须在数据库连接 URL 中启用 rewriteBatchedStatements=true。
MySQL 连接 URL 必须加这个参数
这是 JDBC 驱动层的开关,不加它,批量更新实际仍被拆成单条执行——每条都走完整解析、权限校验、日志刷盘流程,性能几乎无提升。
- 正确写法(Spring Boot
application.yml):
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai
- 驱动版本要求:MySQL 8.0+ 推荐用
mysql-connector-java:8.0.33+;5.x 版本需 ≥ 5.1.13 - 注意:该参数对
INSERT、UPDATE、DELETE全部有效,不只是插入
MyBatis 层要配 BATCH 执行器
让 MyBatis 把多条 update() 调用暂存,再统一交给 JDBC 批处理接口。
立即学习“Java免费学习笔记(深入)”;
- 全局配置(推荐,
mybatis-config.xml):
<settings>
<setting name="defaultExecutorType" value="BATCH"/>
</settings>
- 代码中手动控制(更灵活):
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 执行多次 update
mapper.update(user1);
mapper.update(user2);
// ...
sqlSession.commit(); // 必须显式提交
XML 中写批量 UPDATE 的两种方式
根据场景选一种,但都要配合上面两个配置才真正高效:
-
方式一:多语句拼接(需同时开
allowMultiQueries=true)
适用于字段更新逻辑差异大、或需逐条控制条件的场景:
<update id="updateBatch" parameterType="java.util.List">
<foreach collection="list" item="item" separator=";">
UPDATE user SET name = #{item.name}, age = #{item.age} WHERE id = #{item.id}
</foreach>
</update>
-
方式二:CASE WHEN 单语句(推荐,无需
allowMultiQueries)
性能更高、兼容性更好,适合主键明确、更新字段一致的场景:
<update id="updateBatchByCase" parameterType="java.util.List">
UPDATE user
SET name = CASE id
<foreach collection="list" item="item">
WHEN #{item.id} THEN #{item.name}
</foreach>
ELSE name END,
age = CASE id
<foreach collection="list" item="item">
WHEN #{item.id} THEN #{item.age}
</foreach>
ELSE age END
WHERE id IN
<foreach collection="list" item="item" open="(" close=")" separator=",">
#{item.id}
</foreach>
</update>
分批处理避免超限和 OOM
即使配置全了,一次性传入 5 万条更新数据仍可能触发 MySQL 的 max_allowed_packet 或 JVM 内存溢出。
- 建议单批控制在 500–2000 条之间(视单条 SQL 长度调整)
- Java 侧边循环、边刷新:
int batchSize = 1000;
for (int i = 0; i mapper.update(userList.get(i));
if ((i + 1) % batchSize == 0) {
sqlSession.flushStatements();
sqlSession.clearCache();
}
}
sqlSession.flushStatements();
sqlSession.commit();


















