当前位置: 首页 > news >正文

深入解析MyBatisPlus批量插入性能瓶颈与优化实战

1. MyBatisPlus批量插入的性能陷阱

第一次用MyBatisPlus的saveBatch方法时,我以为找到了批量插入的终极解决方案。直到某天凌晨3点收到报警短信,看到监控图表上那条直冲天花板的数据库响应曲线,才发现自己掉进了"伪批量插入"的坑里。当时我们的物联网平台每秒要处理上千条传感器数据,理论上1500条/批的插入操作应该很轻松,结果MySQL服务器CPU直接飙到100%。

打开MyBatisPlus 3.4.3的源码,saveBatch方法的真面目让人哭笑不得:

public boolean saveBatch(Collection<T> entityList, int batchSize) { return executeBatch(entityList, batchSize, (sqlSession, entity) -> { sqlSession.insert(sqlStatement, entity); }); }

这哪里是批量插入?分明是把List拆成单个对象循环insert!虽然通过sqlSession.flushStatements()做了分批提交,但本质上还是在用单条SQL反复操作。就像用卡车运沙子,表面上看是一车一车地拉,实际上每次只运一粒沙。

真正的性能杀手在于JDBC的默认行为。即使你配置了batchSize,MySQL驱动在不开启rewriteBatchedStatements参数时,会把executeBatch()自动拆解成单条语句执行。这就好比你去快餐店点10个汉堡,服务员不是一次性给你,而是做完一个递一个,再做一个再递一个...

2. 揭开rewriteBatchedStatements的神秘面纱

在JDBC连接串加上rewriteBatchedStatements=true后,奇迹发生了。同样的5万条数据,插入时间从15秒降到3秒。这个参数到底对SQL做了什么魔法?

开启后,JDBC驱动会把多条INSERT语句重写成单条多值语法:

/* 改写前 */ INSERT INTO user(name) VALUES('a'); INSERT INTO user(name) VALUES('b'); /* 改写后 */ INSERT INTO user(name) VALUES('a'),('b');

但要注意三个关键点:

  1. 驱动版本:必须使用MySQL Connector/J 5.1.13以上
  2. 批处理大小:建议每批1000-3000条,太大反而会降低性能
  3. 事务控制:批量操作要放在同一个事务中,避免自动提交

我在测试环境做了组对比实验:

参数配置5万条数据耗时网络请求次数
默认参数15.2s50000
仅rewriteBatchedStatements3.1s50
全优化配置2.7s1

3. 真正的批量插入方案

rewriteBatchedStatements只是解决了JDBC层的问题,MyBatisPlus自身的saveBatch仍然存在循环插入的缺陷。好在官方提供了InsertBatchSomeColumn注入器,这才是SQL层面的真批量插入。

实现步骤比想象中简单:

3.1 自定义SQL注入器

public class MySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); methodList.add(new InsertBatchSomeColumn( field -> field.getFieldFill() != FieldFill.UPDATE)); return methodList; } }

3.2 扩展BaseMapper接口

public interface CommonMapper<T> extends BaseMapper<T> { int insertBatchSomeColumn(@Param("list") List<T> batchList); }

3.3 配置类注册注入器

@Configuration public class MybatisPlusConfig { @Bean public MySqlInjector sqlInjector() { return new MySqlInjector(); } }

现在你的Mapper就拥有了真正的批量插入能力。看下SQL日志会发现本质区别:

-- saveBatch生成的SQL INSERT INTO user(name) VALUES('a'); INSERT INTO user(name) VALUES('b'); -- insertBatchSomeColumn生成的SQL INSERT INTO user(name) VALUES('a'),('b');

4. 高并发场景下的分批策略

直接使用insertBatchSomeColumn有个致命问题——它不支持分批插入。当你要插入10万条数据时,会生成包含10万个VALUES的超级SQL,很可能超过MySQL的max_allowed_packet限制。

参考MyBatisPlus的saveBatch思路,我改造了个支持分批的增强版:

@Transactional(rollbackFor = Exception.class) public boolean saveBatchEnhanced(Collection<T> entityList, int batchSize) { List<T> batchList = new ArrayList<>(); int count = 0; for (T entity : entityList) { batchList.add(entity); if (++count % batchSize == 0 || count == entityList.size()) { baseMapper.insertBatchSomeColumn(batchList); batchList.clear(); } } return true; }

这个方案结合了两种优势:

  1. 每批数据通过insertBatchSomeColumn走真正的批量插入
  2. 通过batchSize控制每批数据量,避免SQL过长

在百万级数据插入测试中,这种方案比原生saveBatch快5-8倍。特别是在物联网设备高频上报数据的场景下,1500条/批的插入耗时稳定在600-800毫秒,再也没出现过Kafka消费者被踢出组的尴尬情况。

5. 性能优化实战对比

为了验证不同方案的实效,我在相同环境下做了组对照实验(测试数据:50万条设备记录):

方案总耗时平均批次耗时内存消耗
原生saveBatch78s1560ms
仅rewriteBatchedStatements32s640ms
insertBatchSomeColumn全量14s280ms
分批insertBatchSomeColumn16s320ms

事实证明,结合rewriteBatchedStatements和分批处理的insertBatchSomeColumn是最优解。虽然全量插入的理论速度最快,但在生产环境风险太高。我的建议是:

  • 开发环境可以用全量插入方便测试
  • 生产环境务必采用分批策略,建议batchSize设为1000-3000
  • 配合连接池参数调优(maxPoolSize、minIdle等)

最后分享个真实案例:某智能家居平台接入10万台设备后,每日数据量达到2亿条。采用优化方案后,批量插入耗时从原来的平均4秒降到800毫秒,服务器资源消耗降低60%。这告诉我们:批量操作无小事,性能优化往往就在这些基础细节里。

http://www.jsqmd.com/news/562877/

相关文章:

  • 深度拆解MySQL InnoDB存储引擎架构:从内存到磁盘的全链路解析
  • FLUX.1-dev像素艺术生成器效果:超分辨率重建前后对比分析
  • 分布式存储的监控与告警:从理论到实践
  • 2023年HCA-Security综合安防考试
  • 项目实训第一次讨论
  • 2026年护栏网应用白皮书畜牧养殖领域解析 - 优质品牌商家
  • Cojson:面向MCU的零分配JSON解析器
  • 220v转24v 32v电流300W电源方案
  • 宝塔面板异地备份数据全攻略:从本地到云端的安全守护
  • UWB(AOA)技术是如何应用在智慧工厂的
  • 7B小模型吊打GPT-5?CarePilot用Actor-Critic范式攻克医疗软件自动化
  • 万用自动连点点击器 v2.2.4解锁版-无需ROOT自动连点
  • CHORD-X效果实测:对比不同参数下生成报告的连贯性与深度
  • XLR8RC库:嵌入式RC信号高精度脉宽捕获方案
  • 金蝶k3软件常用基础SQL数据表
  • 在Ubuntu 20.04上搞定创龙T113 SDK编译:我踩过的那些Python和gdbus的坑
  • FastbootEnhance:Windows上最直观的Fastboot工具箱与Payload提取器
  • 2026镇海区空调及进口热水器维修行业白皮书 - 优质品牌商家
  • 告别PXE!用iPXE在CentOS 8.5上搭建一个能同时装Win11和Linux的万能网络启动盘
  • 2026年保温卷帘门公司权威推荐:成都卷帘门/电动保温卷帘门/电动卷帘门/车库保温卷帘门/车库卷帘门/选择指南 - 优质品牌商家
  • 告别串口接收烦恼!手把手配置华大HC32F460的UART超时中断(附RT-Thread驱动示例)
  • 【Frida Android】实战篇:Frida-Trace 进阶追踪——JNI 函数调用栈与参数解析
  • 崩溃体验馆:付费观赏系统死机的艺术
  • 如何通过FastbootEnhance实现Android设备快速刷机与分区管理
  • 概率预测实战 —— DeepAR 模型在电力负荷预测中的应用
  • 别再傻傻用相机了!用海康VisionMaster本地图片也能跑算法,附完整配置流程
  • 稳定的第三方软件库
  • GitHub Desktop 中文界面突破方案:告别语言障碍的效率革命
  • 三步搞定全网资源下载:揭秘智能嗅探工具如何让你轻松捕获视频与图片
  • Kook Zimage真实幻想Turbo应用探索:心理疗愈领域幻想意象可视化工具