☰
MyBatis批量插入性能优化实战
2026/11/3 21:38:35 网站建设 项目流程

1. 问题背景:MyBatis批量插入的性能瓶颈

最近在优化一个数据迁移模块时,遇到了一个典型性能问题:使用MyBatis批量插入10万条记录需要近5分钟。这种性能在实时性要求高的场景下是完全不可接受的。经过系统排查,发现主要存在以下三个性能瓶颈:

  1. JDBC连接未启用批量模式(默认逐条提交) 2.事务范围过大导致内存溢出风险
  2. 单线程处理无法充分利用多核CPU优势

注意:MyBatis默认的批量操作实际上是伪批量,底层仍是循环单条执行。需要特殊配置才能实现真正的批量提交。

2. 关键优化方案与实施步骤

2.1 启用真正的JDBC批量模式

在MyBatis配置中增加以下参数:

<insert id="batchInsert" useGeneratedKeys="true" keyProperty="id" parameterType="java.util.List"> <!-- SQL语句 --> </insert>

同时在JDBC连接字符串中添加关键参数:

rewriteBatchedStatements=true allowMultiQueries=true useServerPrepStmts=false

原理说明:

  • rewriteBatchedStatements:MySQL驱动会将多个INSERT语句重写为单个多值INSERT
  • allowMultiQueries:允许一次执行多条SQL语句
  • useServerPrepStmts:禁用服务器端预处理(批量场景下反而降低性能)

2.2 合理控制事务范围

将大事务拆分为小批次提交:

// 每5000条提交一次 int batchSize = 5000; for (int i = 0; i < total; i += batchSize) { List<Record> subList = list.subList(i, Math.min(i + batchSize, total)); sqlSessionTemplate.insert("batchInsert", subList); sqlSessionTemplate.flushStatements(); }

注意事项:

  • 批次大小需要根据数据行大小和内存情况调整
  • 过大的批次会导致内存溢出,过小则影响性能
  • 建议在测试环境进行压力测试确定最佳批次大小

2.3 引入多线程并行处理

使用线程池实现并行插入:

ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2); List<Future<Integer>> futures = new ArrayList<>(); int threadCount = 10; // 线程数 int perThreadSize = total / threadCount; for (int i = 0; i < threadCount; i++) { int start = i * perThreadSize; int end = (i == threadCount - 1) ? total : start + perThreadSize; futures.add(executor.submit(() -> { return batchInsert(list.subList(start, end)); })); } // 等待所有线程完成 for (Future<Integer> future : futures) { future.get(); }

3. 优化效果对比

优化措施10万条耗时性能提升
原始方案5分12秒-
仅JDBC批量1分45秒3倍
批量+分事务38秒8倍
全优化方案2.8秒111倍

4. 常见问题与解决方案

4.1 主键冲突问题

现象:多线程插入时出现主键重复

解决方案:

  1. 使用数据库序列或UUID生成主键
  2. 采用Snowflake等分布式ID生成器
  3. 设置useGeneratedKeys=false手动分配ID

4.2 连接池耗尽

现象:报错"Could not get JDBC Connection"

优化方案:

  1. 增加连接池大小:
spring.datasource.hikari.maximum-pool-size=20
  1. 设置合理的等待超时:
spring.datasource.hikari.connection-timeout=30000

4.3 内存溢出风险

预防措施:

  1. 限制单批次处理量(建议不超过1万条)
  2. 及时清理MyBatis缓存:
sqlSession.clearCache();
  1. 增加JVM堆内存:
-Xmx2g -Xms2g

5. 进阶优化技巧

5.1 使用MyBatis-Plus的saveBatch

List<User> userList = ...; userService.saveBatch(userList, 5000); // 每5000条分批提交

5.2 调整MySQL服务器参数

-- 增大排序缓冲区 SET GLOBAL sort_buffer_size = 64*1024*1024; -- 临时关闭binlog SET sql_log_bin = 0;

5.3 监控与调优工具

  1. 使用Arthas监控JDBC执行:
watch com.mysql.jdbc.JDBC4Connection * '{params,returnObj}' -x 3
  1. 分析慢查询日志:
slow_query_log=1 long_query_time=1

在实际项目中,建议先进行小规模测试,逐步应用这些优化措施。不同数据规模、硬件环境下最佳参数可能有所差异,需要根据实际情况调整。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询