executortype.batch能显著提速,因其复用preparedstatement、合并网络往返与事务,将万条插入从30秒+压缩至1秒内;需正确执行获取会话、循环入队、分批flush、最终commit四步,并配合rewritebatchedstatements等jdbc参数。

核心就一条:用 ExecutorType.BATCH 替代默认的 Simple 模式,让多条 SQL 合并提交,而不是每条都单独走一遍连接、解析、执行、事务流程。
为什么批量操作能快几十倍?
普通循环插入 1 万条数据,本质是:
- 发起 10,000 次 JDBC 请求,每次都要建连接、发 SQL、等响应;
- 数据库为每条语句写 WAL 日志、刷盘、做约束检查;
- MyBatis 默认 Simple 模式下,每个 insert 都新建 PreparedStatement,开销巨大。
而 BatchExecutor 模式下:
- 复用同一个 PreparedStatement;
- 调用
addBatch()缓存 SQL 参数,不立即执行; - 直到
flushStatements()或commit()才统一调用executeBatch()发送给数据库; - 网络往返从上万次降到几十次,事务合并,日志批量写入。
正确使用 BatchExecutor 的关键步骤
必须按顺序做对这四件事,缺一不可:
- 用
sqlSessionFactory.openSession(ExecutorType.BATCH)获取会话; - 循环调用 mapper 方法(如
mapper.insert(user)),此时只是入队,不执行; - 每 500~1000 条调用一次
sqlSession.flushStatements(),防内存溢出和锁表过久; - 全部处理完后,显式调用
sqlSession.commit()提交,并在finally中close()。
几个容易踩的坑
不是开了 BATCH 就万事大吉,这些细节决定成败:
-
不能获取自增主键:
useGeneratedKeys="true"在 BATCH 模式下失效,如需 ID,得改用 UUID 或数据库序列; - 别忘了关会话:不 close 会导致连接泄漏,严重时拖垮整个应用;
-
异常必须 rollback:捕获到异常后要手动
rollback(),否则脏数据可能残留; -
慎用自动提交:创建会话时传
false(如openSession(ExecutorType.BATCH, false)),避免每条都自动 commit。
配合 JDBC 参数效果更佳
光靠 MyBatis 不够,底层驱动也要调优:
- MySQL 连接 URL 加上
?rewriteBatchedStatements=true,驱动会把多条 INSERT 合并成一条原生批量语句; - MyBatis 配置里设
<setting name="jdbc.batch_size" value="1000"></setting>,控制默认批次大小; - 连接池(如 HikariCP)配置合理最小/最大连接数,避免批量时抢不到连接。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











