1. 为什么MyBatis批量插入需要优化在数据量较大的业务场景中批量插入操作是数据库性能优化的关键点。很多开发者习惯使用MyBatis的foreach标签来实现批量插入这其实是一个典型的性能陷阱。我曾在电商平台的订单系统中因为这个问题导致高峰期数据库连接池被耗尽后来通过深入分析找到了更优方案。1.1 foreach方式的性能瓶颈foreach方式的典型写法是这样的insert idbatchInsert INSERT INTO user(name,age) VALUES foreach collectionlist itemitem separator, (#{item.name},#{item.age}) /foreach /insert这种写法会产生一个超长的SQL语句比如插入1000条记录就会生成包含1000个VALUES子句的SQL。主要问题在于SQL长度限制某些数据库对SQL语句长度有限制MySQL默认是4MB网络传输开销大SQL需要更多网络传输时间解析成本高数据库需要解析超长SQL消耗CPU资源事务回滚困难如果中间某条记录出错整个批量操作都会失败1.2 更优的Batch模式方案MyBatis其实内置了更高效的批量处理机制 - BatchExecutor。通过调整ExecutorType为BATCH可以实现真正的批处理操作SqlSession session sqlSessionFactory.openSession(ExecutorType.BATCH); try { UserMapper mapper session.getMapper(UserMapper.class); for (User user : userList) { mapper.insert(user); } session.commit(); } finally { session.close(); }这种方式会预编译SQL语句一次多次发送参数集合最后统一提交显著减少网络往返和SQL解析开销2. 三种执行器类型深度对比MyBatis提供了三种ExecutorType理解它们的区别对性能优化至关重要2.1 SIMPLE执行器默认模式每次执行都会创建新的PreparedStatement对象。适合常规的单条操作但在批量场景下性能最差。2.2 REUSE执行器重用PreparedStatement对象对于相同的SQL语句只会预编译一次。比SIMPLE模式节省了预编译开销但每次执行仍然会单独发送到数据库。2.3 BATCH执行器真正的批处理模式会将多个操作合并后一次性发送。实测在插入1000条记录时性能比foreach方式提升3-5倍。执行器类型预编译次数网络请求次数适用场景SIMPLE每次执行每次执行常规单条操作REUSE首次执行每次执行相同SQL频繁执行BATCH首次执行批量提交大批量写操作3. 实战批量插入性能优化方案3.1 基础Batch模式实现public void batchInsert(ListUser users) { SqlSession session sqlSessionFactory.openSession(ExecutorType.BATCH); try { UserMapper mapper session.getMapper(UserMapper.class); for (User user : users) { mapper.insert(user); } session.commit(); } catch (Exception e) { session.rollback(); throw e; } finally { session.close(); } }关键点使用ExecutorType.BATCH创建SqlSession在循环中调用mapper方法最后统一commit必须处理异常和资源释放3.2 分批次提交优化对于超大数量级的批量插入如10万建议分批次提交public void batchInsert(ListUser users, int batchSize) { SqlSession session sqlSessionFactory.openSession(ExecutorType.BATCH); try { UserMapper mapper session.getMapper(UserMapper.class); for (int i 0; i users.size(); i) { mapper.insert(users.get(i)); if (i % batchSize 0 || i users.size() - 1) { session.commit(); session.clearCache(); // 防止OOM } } } finally { session.close(); } }3.3 与Spring集成方案在Spring环境中可以通过配置注入Batch模式的SqlSessionTemplateBean public SqlSessionTemplate batchSqlSessionTemplate() { return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH); } Service public class UserService { Autowired Qualifier(batchSqlSessionTemplate) private SqlSessionTemplate sqlSessionTemplate; public void batchInsert(ListUser users) { UserMapper mapper sqlSessionTemplate.getMapper(UserMapper.class); // ...批量操作逻辑 } }4. 性能实测与对比数据我在本地环境MySQL 5.7100M网络进行了三种方式的性能对比测试操作方式1000条耗时(ms)10000条耗时(ms)内存占用foreach1200超时(60s)高SIMPLE8507800中BATCH2802100低关键发现小批量时(100条内)差异不大超过500条时BATCH优势明显foreach方式在大批量时完全不可用5. 常见问题与解决方案5.1 批量操作获取主键ID使用Batch模式时无法像常规插入那样立即获取生成的主键。解决方案预先分配ID如UUID或雪花算法批量插入后通过查询条件获取使用数据库特定语法如MySQL的LAST_INSERT_ID(expr)5.2 事务管理注意事项Batch模式的事务是统一提交的中间出错会全部回滚在Spring中需要将事务管理器与Batch模式配合使用考虑使用编程式事务控制更精细的提交点5.3 内存溢出预防长时间运行的批量操作可能导致内存溢出定期clearCache()分批次提交监控JVM内存使用考虑使用游标方式处理超大数据集6. 高级优化技巧6.1 JDBC参数调优在连接字符串中添加批处理优化参数rewriteBatchedStatementstrue allowMultiQueriestrue useServerPrepStmtstrue cachePrepStmtstrue6.2 批量大小选择最优批量大小取决于数据库类型MySQL/Oracle等网络延迟记录字段大小通常500-2000是不错的起点6.3 多线程批量插入对于超大数据集可以结合线程池并行处理ExecutorService executor Executors.newFixedThreadPool(4); ListFuture? futures new ArrayList(); int perThread totalSize / 4; for (int i 0; i 4; i) { int from i * perThread; int to (i 3) ? totalSize : (i1)*perThread; futures.add(executor.submit(() - batchInsert(users.subList(from, to)))); } for (Future? future : futures) { future.get(); }7. 不同数据库的特别优化7.1 MySQL优化使用rewriteBatchedStatements参数考虑LOAD DATA INFILE替代SQL插入调整max_allowed_packet参数7.2 Oracle优化使用OCI批处理接口考虑数组绑定方式调整SESSION_CACHED_CURSORS参数7.3 PostgreSQL优化使用COPY命令替代INSERT调整work_mem参数考虑使用UNNEST函数8. 监控与问题排查8.1 性能监控指标批处理执行时间批处理成功率数据库服务器CPU/内存使用网络IO情况8.2 常见错误排查批量过大导致内存溢出减小batchSize部分失败导致全部回滚检查数据有效性性能未达预期检查JDBC参数和网络状况主键冲突确保ID生成策略正确9. 替代方案评估9.1 MyBatis-Plus的批量操作MyBatis-Plus提供了更简洁的批量操作方法userService.saveBatch(userList, batchSize);9.2 原生JDBC批处理对于极致性能需求可以考虑直接使用JDBC批处理Connection conn dataSource.getConnection(); PreparedStatement ps conn.prepareStatement(INSERT...); for (User user : users) { ps.setString(1, user.getName()); // ...其他参数 ps.addBatch(); } ps.executeBatch();9.3 数据库特有批量工具MySQL的LOAD DATA INFILEOracle的SQL*LoaderPostgreSQL的COPY命令10. 最佳实践总结经过多个项目的实践验证我总结出以下最佳实践小于100条可以使用foreach方式代码简单100-5000条使用MyBatis Batch模式5000条分批次使用Batch模式10万条考虑数据库特有批量工具始终监控内存使用和性能指标根据数据库类型调整优化参数在测试环境验证批量大小阈值实现优雅的失败处理和重试机制
企业数字化 ERP 产品动态
相关推荐
从零开始学AI工程:数据到部署的完整闭环 如果你也想走“从零开始”学AI工程这条路,先别急着收藏一堆论文。ai-engineering-from-scratch这个词我盯了很久,它看起来像一个开源仓库名,实际上更像一种学习思路:不靠调用现成服务“假装会了”,而是把数据、训练、部… · 2026/11/3 4:59:53
高校学工一体化平台架构设计与智能应用实践 1. 学工一体化平台的核心定位与价值学工一体化平台是高校学生工作数字化转型的核心载体,它通过整合教务、学籍、资助、心理、就业等十余个业务模块,实现了学生从入学到毕业的全生命周期管理。这种系统不同于传统的教务管理系统,其核心差异在于… · 2026/11/3 4:58:53
如何制造真正的Buzz?从情绪洞察到引爆节奏的全流程拆解 1. Buzz到底是什么:拆开来看的热度密码聊buzz之前,先说个我观察到的现象。这几年我接触了不少团队和品牌方,一说要做buzz,第一反应都是“我们要搞个大事件”“找个热点蹭一波”。结果十次有八次,钱花了,KOL… · 2026/11/3 4:58:53
Temu电商平台商业模式分析与用户画像研究 1. Temu的90天:谁在买单?Temu作为一家新兴的电商平台,在短短90天内迅速崛起,引发了广泛关注。这个标题背后隐藏着一个核心问题:究竟是什么人在为Temu的快速增长买单?是消费者、供应商,还是资本市… · 2026/11/3 5:30:03
Ubuntu 16.04 Redis 单机与六节点集群搭建及投票后端实战 简介:南邮大数据存储与管理实验一配套文档面向大数据、存储管理课程学生及Redis初学者,聚焦在Ubuntu 16.04下完成Redis单机与集群环境安装配置,并基于Redis构建简单文章投票网站后端,用于课程实验复现与实验报告撰写参考。包内仅含… · 2026/11/3 5:30:03
投机解码加速的真相:瓶颈份额决定端到端收益 投机解码这几年的热度一直不降,从LLM推理服务到端侧部署,到处都能看到“xx倍加速”的宣传数字。但说实话,我日常接触到的很多项目,真正把投机解码大规模落地到生产环境,反而很少能复现出论文里的加速比。仔细追下去&am… · 2026/11/3 5:30:03
浏览器MCP实战:让AI接管网页导航、点击与数据采集的自动化指南 最近被我那台“会自己干活”的浏览器折腾得有点上头。起因是我想让 AI 帮我巡检十几个网页状态,再整理成报告。以前这种活无非两条路:要么写 Playwright 脚本,要么自己手动一个个开页面看。脚本要维护,手动看要命。后来我换成 MCP… · 2026/11/3 5:30:03
Docker容器化部署Redis的最佳实践与优化策略 1. Redis与Docker的黄金组合:为什么选择容器化部署Redis作为当今最流行的内存数据库之一,其高性能、低延迟的特性使其成为缓存、会话存储和实时数据分析的首选方案。而Docker的轻量级容器技术,则为Redis的部署和管理带来了革命性的便利。传统… · 2026/11/3 5:30:03
CPS/SPS系统包结构设计与多模块工程实践 1. 为什么CPS/SPS系统需要特别关注包结构设计在电商和供应链领域摸爬滚打多年后,我深刻体会到CPS(Cost Per Sale)和SPS(Supply Platform System)这类系统的复杂性。与普通业务系统不同,它们通常需要同时处理… · 2026/11/3 5:29:02
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18