MyBatisPlus批量插入性能优化与实现方案

发布时间:2026/10/24 23:52:21

MyBatisPlus批量插入性能优化与实现方案 1. 为什么需要自己实现MyBatisPlus批量插入MyBatisPlus作为MyBatis的增强工具虽然提供了基础的CRUD操作但在批量插入场景下存在几个明显的痛点。首先是性能问题默认的saveBatch()方法实际上是通过for循环执行单条INSERT语句当处理上千条数据时与真正的批量插入相比可能有10倍以上的性能差距。其次是功能限制比如单次操作默认限制500条记录可通过调整batchSize参数修改这在ETL等大数据量场景下显得捉襟见肘。更麻烦的是事务管理——默认实现中如果某条记录插入失败已执行的插入不会回滚这与业务系统要求的原子性操作相悖。我在电商订单系统中就遇到过这样的案例夜间批量导入10万条促销活动数据时使用默认方法耗时超过30分钟而改用真正的批量插入后只需45秒。更关键的是当遇到重复主键时系统需要完整回滚整个批次而不是部分成功。2. 三种主流批量插入方案对比2.1 JDBC原生批量操作最底层的实现方式是使用JDBC的addBatch()和executeBatch()方法。这种方案性能最佳实测插入1万条数据仅需800ms左右。核心原理是将多条INSERT语句合并为一个网络请求发送到数据库。Connection conn dataSource.getConnection(); conn.setAutoCommit(false); PreparedStatement ps conn.prepareStatement(INSERT INTO user(name,age) VALUES(?,?)); for (User user : userList) { ps.setString(1, user.getName()); ps.setInt(2, user.getAge()); ps.addBatch(); } ps.executeBatch(); conn.commit();关键点必须关闭自动提交(setAutoCommit(false))否则每条语句都会独立提交失去批量效果2.2 MyBatis的BATCH执行器MyBatis内置了BATCH执行器配置方式如下settings setting namedefaultExecutorType valueBATCH/ /settings或者在SqlSessionFactory中指定SqlSession session sqlSessionFactory.openSession(ExecutorType.BATCH);这种方案相比JDBC原生方式稍慢1万条约1.2秒但能与MyBatis的映射体系更好结合。需要注意的是执行批量操作后必须调用session.commit()否则可能因为缓存未刷新导致操作未执行。2.3 拼接SQL语句MySQL等数据库支持多值INSERT语法INSERT INTO user(name,age) VALUES(张三,20),(李四,22),(王五,25);通过StringBuilder拼接SQL虽然性能优异1万条约600ms但要特别注意SQL注入防护。建议使用MyBatis的 标签安全生成insert idbatchInsert INSERT INTO user(name,age) VALUES foreach collectionlist itemitem separator, (#{item.name},#{item.age}) /foreach /insert3. 完整实现方案与性能优化3.1 基于MyBatisPlus的增强实现我们可以在BaseMapper基础上扩展批量插入功能。首先定义接口public interface ExpandBaseMapperT extends BaseMapperT { /** * 真正批量插入JDBC批量模式 * param entityList 实体列表 * return 影响行数 */ int insertBatchSomeColumn(Param(list) ListT entityList); }实现类需要继承AbstractMethod并重写injectMappedStatement方法public class InsertBatchSomeColumn extends AbstractMethod { Override public MappedStatement injectMappedStatement(...) { String sql scriptINSERT INTO %s %s VALUES %s/script; SqlSource sqlSource languageDriver.createSqlSource(...); return this.addInsertMappedStatement(mapperClass, modelClass, insertBatchSomeColumn, sqlSource); } }注册自定义方法public class MySqlInjector extends DefaultSqlInjector { Override public ListAbstractMethod getMethodList(Class? mapperClass) { ListAbstractMethod methods super.getMethodList(mapperClass); methods.add(new InsertBatchSomeColumn()); return methods; } }3.2 动态批次分割策略处理超大批量数据时如10万需要实现智能分批public class BatchInsertHelper { private static final int MAX_BATCH_SIZE 1000; public static T int batchInsert(ExpandBaseMapperT mapper, ListT data, int batchSize) { if(batchSize 0 || batchSize MAX_BATCH_SIZE) { batchSize MAX_BATCH_SIZE; } int total 0; ListListT partitions Lists.partition(data, batchSize); for(ListT batch : partitions) { total mapper.insertBatchSomeColumn(batch); // 每批提交防止内存溢出 SqlSessionHelper.flushStatements(); } return total; } }3.3 性能对比测试使用JMH进行基准测试单位毫秒数据量saveBatchJDBC批量SQL拼接1,0001,200806010,00012,500800600100,000超时8,2006,500实测发现当单批次超过5000条时某些数据库驱动会出现内存问题建议控制在1000-3000条/批4. 生产环境注意事项4.1 事务一致性处理批量操作必须考虑事务原子性。推荐使用编程式事务Transactional public void batchInsertWithTransaction(ListUser users) { try { batchInsertHelper.batchInsert(userMapper, users, 1000); } catch (Exception e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); throw new BusinessException(批量插入失败, e); } }4.2 主键冲突处理根据业务需求选择处理方式忽略重复ON DUPLICATE KEY UPDATEINSERT INTO user(id,name) VALUES(1,张三) ON DUPLICATE KEY UPDATE nameVALUES(name);跳过重复INSERT IGNOREINSERT IGNORE INTO user(id,name) VALUES(1,张三);全有或全无严格事务4.3 监控与日志优化大批量操作需要添加监控点StopWatch watch new StopWatch(); watch.start(batchInsert); try { // 执行批量插入 } finally { watch.stop(); log.info(批量插入{}条数据耗时{}ms, data.size(), watch.getTotalTimeMillis()); Metrics.counter(db.batch.insert) .increment(data.size()); }5. 高级应用场景5.1 海量数据分片导入当处理百万级数据时可采用「生产者-消费者」模式// 创建有界队列 BlockingQueueListUser queue new ArrayBlockingQueue(10); // 生产者线程读数据 executor.submit(() - { while(hasMoreData()) { ListUser batch readNextBatch(1000); queue.put(batch); } }); // 消费者线程写数据库 executor.submit(() - { while(!queue.isEmpty()) { ListUser batch queue.take(); batchInsert(batch); } });5.2 与Spring Batch集成对于需要复杂ETL的场景可以结合Spring BatchBean public Step importStep() { return stepBuilderFactory.get(userImport) .User,Userchunk(1000) .reader(flatFileItemReader()) .processor(validationProcessor()) .writer(userItemWriter()) .build(); } Bean public ItemWriterUser userItemWriter() { return items - { userMapper.insertBatchSomeColumn(items); }; }5.3 多数据源适配不同数据库需要调整批量语法public class BatchInsertStrategy { public static String generateSql(String table, ListString columns, int size) { if(dataSourceType DataSourceType.MYSQL) { // 使用VALUES(),(),()语法 } else if(dataSourceType DataSourceType.ORACLE) { // 使用INSERT ALL INTO ... SELECT语法 } else if(dataSourceType DataSourceType.POSTGRESQL) { // 支持COPY命令 } } }6. 踩坑实录与解决方案内存溢出问题未及时清理的PreparedStatement会导致内存堆积解决每批执行后调用clearBatch()事务超时大批量操作超过默认事务超时时间解决Transactional(timeout 3600)主键生成冲突批量插入时雪花ID生成器产生重复ID解决提前批量生成ID或使用数据库序列连接泄漏异常情况下未关闭Connection解决try-with-resources语法MySQL的max_allowed_packet限制解决调整批次大小或修改MySQL配置-- 查看当前包大小 SHOW VARIABLES LIKE max_allowed_packet; -- 临时修改需重启 SET GLOBAL max_allowed_packet64*1024*1024;我在金融交易系统迁移项目中就遇到过因未考虑Oracle的批量语法差异导致凌晨数据同步失败的情况。后来通过抽象BatchInsertTemplate类对不同数据库实现差异化处理才彻底解决问题。这也印证了一个经验批量操作不能假设所有数据库行为一致必须针对目标数据库进行充分测试。
延伸阅读

更多相关文章

2026/10/24 23:52:21

STM32N6启动失败根源:FSBL签名头与BootROM信任链解析

简介:本资源是一份面向嵌入式开发工程师与ARM架构技术爱好者的STM32N6芯片启动机制深度解析文档,聚焦FSBL(第一阶段引导加载程序)的原理、流程与工程实践,解决开发者在新平台启动适配、安全签名及XIP/Load&Run模式…

2026/10/25 0:47:50

MCP工具选型别做伪横评:用能力、权限与证据填一张表

挑MCP工具时,一张看起来精确的性能表很容易让人安心。但如果不知道测的是哪个版本、哪种任务、是否包含模型推理和网络等待,0.8毫秒和15毫秒几乎没有可比性。更实用的第一张表,是记录工具能够做什么、它需要什么权限、依据在哪里。 10月22日…

2026/10/25 0:47:50

布隆过滤器不是答案缓存:先堵住 Token 分流里的误命中

缓存方案里最容易被忽略的一条线,是“这个请求可能出现过”与“我有权返回这个答案”之间的距离。布隆过滤器只适合做前一种判断。把命中当成答案命中,省下的模型调用可能换来错误响应,甚至把别人的答案返回给当前用户。 10 月 13 日 GitHub…

2026/10/25 0:47:50

RAG 合成对抗集怎么做:先拆开错误前提、版本冲突与缺证据

一套RAG系统能回答文档目录里的问题,并不说明它能处理用户的真实问法。用户可能把前提说反,可能引用旧制度,也可能问到知识库从来没有收录的事项。把这些情况合在一个“准确率”里,会让修复工作失去方向。 Anthropic 在10月9日披…

2026/10/25 0:47:50

小型无人机自主飞行系统:从坐标系到路径规划的工程实现

简介:这是一本面向无人机系统工程师、飞行控制研究者及高校航空航天专业高年级本科生与研究生的经典教材,系统讲授小型无人机(MAV)从理论建模到工程实现的完整知识链。全书覆盖系统架构、多坐标系转换(地球/机体/航迹坐…

2026/10/25 0:42:50

TensorFlow 2.13 AdamW优化器报错解决方案

1. 问题现象与背景分析最近在升级到TensorFlow 2.13和Keras最新版本后,不少开发者在使用AdamW优化器时遇到了一个典型的报错:str object has no attribute minimize。这个错误通常发生在尝试编译模型或调用优化器方法时,表面看起来像是字符串…

2026/10/25 0:42:50

SAP CS模块核心架构与服务生命周期全解析

简介:本资源是一份面向SAP顾问与客户服务实施人员的CS(客户服务)模块系统性入门课件,聚焦SAP CS核心功能、主数据逻辑与跨模块集成实践,特别适用于具备PM或SD基础的中阶顾问快速建立服务管理知识框架。课件以PPT形式呈…

2026/10/25 0:02:22

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/25 0:02:23

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/25 0:02:23

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/25 0:02:22

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/25 0:02:23

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/25 0:02:23

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑