mybatis的executortype.batch并非高性能银弹,仅提供缓存+延迟执行机制;真正高性能需绕过其限制(如单statement复用、无预编译等),配合jdbc批量参数(如mysql的rewritebatchedstatements=true)及合理分片。

MyBatis 的 ExecutorType.BATCH 本身**不是“高性能批处理”的银弹**,它只是开启了一种缓存+延迟执行的机制;真正高性能的批处理,取决于你是否绕开了它的默认限制(如单 Statement 复用、无预编译批量、不自动 flush 等),并配合 JDBC 层的批量能力(如 MySQL 的 rewriteBatchedStatements=true)和合理分片策略。
理解 BATCH 执行器的真实行为
MyBatis 的 BATCH 执行器并不会自动把多条 INSERT 合成一条 SQL(如 INSERT INTO t VALUES(...),(...),(...))。它实际做的是:
- 复用同一个
PreparedStatement对象(同一 SQL 模板) - 调用
ps.addBatch()缓存参数批次 - 直到
sqlSession.flushStatements()或sqlSession.commit()时才真正触发ps.executeBatch() - **不支持跨 SQL 模板批处理**(比如不能把 INSERT 和 UPDATE 混在一个 batch)
必须配置的 JDBC 参数(以 MySQL 为例)
仅靠 MyBatis 的 BATCH 不足以提速。关键在 JDBC 驱动是否将多个 addBatch() 转为底层真正的批量协议:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
MySQL 必须加参数:
rewriteBatchedStatements=true(否则驱动仍会发送 N 条独立语句) - 推荐补充:
useServerPrepStmts=false(避免服务端预编译开销)、cachePrepStmts=true - 连接池(如 HikariCP)建议设置
connectionInitSql=SET SESSION autocommit = 0,减少事务开销
URL 示例:jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true&useServerPrepStmts=false&cachePrepStmts=true
正确使用 SqlSession + BATCH 的写法
避免常见错误:直接用 SqlSessionTemplate 或 Spring 管理的 session(默认是 SIMPLE),必须手动获取非托管的 SqlSession 并指定类型:
- ✅ 正确方式(原生 MyBatis):
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
for (User user : userList) {
mapper.insert(user); // 只 addBatch,不执行
}
sqlSession.flushStatements(); // 触发 executeBatch()
sqlSession.commit(); // 提交事务(含 flush)
}
- ❌ 错误方式:用
@Mapper接口 + Spring@Transactional默认 session —— 它不会用 BATCH 执行器 - ⚠️ 注意:每 500~1000 条调用一次
flushStatements(),防内存溢出;不要等最后 commit 才 flush
进一步提升性能的实战技巧
-
手写多值 INSERT(推荐):用
<foreach></foreach>生成INSERT INTO ... VALUES (...),(...),(...),单条 SQL 插入百条,比 BATCH 更快(尤其数据量 -
分片提交:每 500 条一个子事务(
flush + commit),避免长事务锁表、GC 压力大 -
关闭一级缓存:BATCH 下一级缓存无意义,可在
openSession时传new ExecutorType.BATCH, false关闭 -
Mapper XML 中禁用
useGeneratedKeys:自增主键会强制每条都执行executeUpdate,破坏 batch 效果;改用数据库序列或 UUID
不复杂但容易忽略:BATCH 的价值不在“省 SQL”,而在减少网络往返和 PreparedStatement 创建开销。真要极致性能,该手写多值就手写,该配 JDBC 就配全,别只依赖 MyBatis 一层封装。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










