mybatis批量插入性能提升的关键是启用executortype.batch并循环调用单条insert方法,而非用拼接大sql;需配合分批、flush、连接参数优化及事务管理。

MyBatis 中批量插入性能提升的关键,不是靠 <foreach></foreach> 拼 SQL 实现“伪批量”,而是要结合 JDBC 批处理机制(ExecutorType.BATCH)与合理的 SQL 写法。单纯用 <foreach></foreach> 生成一条含上千 values 的 INSERT 语句,容易触发数据库限制、内存溢出,且无法复用预编译、事务粒度难控。
✅ 正确方式:开启 BATCH Executor + 单条 insert 语句循环 add
这是 MyBatis 官方推荐的高效批量操作模式,底层调用 JDBC 的 addBatch() 和 executeBatch():
- SqlSession 必须使用
ExecutorType.BATCH构建(不能用默认的 SIMPLE) - Mapper 接口方法仍写单条 insert(如
insertUser(User user)),不带<foreach></foreach> - Java 代码中循环调用该方法,MyBatis 会自动攒批,直到 commit 或手动 flush
- 建议每 1000 条左右
sqlSession.flushStatements()避免内存堆积
⚠️ foreach 拼接批量 INSERT 的适用场景和风险
<foreach></foreach> 适合「中小批量」(如 ≤ 500 条)、对事务一致性要求高、且数据库支持多值 INSERT(MySQL 支持,Oracle 不原生支持)的场景:
- SQL 示例:
INSERT INTO user (name, age) VALUES <foreach item="u" collection="list"> (#{u.name}, #{u.age})<choose><when test="not last">,</when></choose></foreach> - 必须配置
useGeneratedKeys="false"(否则主键回填失效) - 注意 MySQL 的
max_allowed_packet限制,超长 SQL 会报错 - Oracle 需改用
INSERT ALL或拆成多条,不能直接套用此写法
⚡ 进阶优化:分批 + BATCH + 异步提交
面对百万级数据,单一事务太重,可组合以下策略:
- 将大 List 拆成子列表(如每 500 条一组)
- 为每组新建一个
SqlSession(ExecutorType.BATCH),执行后立即 close/commit - 用线程池并发处理多批次(注意数据库连接数和事务隔离影响)
- 关闭一级缓存(
sqlSession.clearCache())避免 GC 压力
? 配置与注意事项
确保以下配置生效,否则 BATCH 模式可能退化:
- MyBatis 配置中
defaultExecutorType不要设为 BATCH(全局设了反而影响普通查询),应按需显式创建 - 数据库连接 URL 加上
&rewriteBatchedStatements=true(MySQL 专用),让驱动将多条 insert 自动优化为底层 batch 指令 - 事务管理交由 Spring 时,
@Transactional方法内不要手动 open Batch SqlSession,应由 Spring 的SqlSessionTemplate管理 - 批量失败时,默认整批回滚;如需部分成功,需捕获
BatchUpdateException并解析getUpdateCounts()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











