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

Mybatis-Plus多种批量插入方案对比

背景

六月某日上线了一个日报表任务,因是第一次上线,故需要为历史所有日期都初始化一次报表数据
在执行过程中发现新增特别的慢:插入十万条左右的数据,SQL执行耗费高达三分多钟

因很早就听闻过mybatis-plus的[伪]批量新增的问题,很快锁定问题并进行修复,下面细节描述多种批量新增方案的具体性能表现

# 测试表结构
DROP TABLE IF EXISTS `biz_batch_insert_test`;
CREATE TABLE `biz_batch_insert_test` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(600) DEFAULT NULL,`age` tinyint(4) unsigned DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;# name字段给的长度大了些,模拟生产实际表结构占用
# 测试库版本:5.7.5

方案一:传统for循环

@Test
public void testUserInsert() {long l = System.currentTimeMillis();for (int i = 0; i < 100000; i++) {TestUser testUser = new TestUser();testUser.setName("中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国");testUser.setAge(20);testUserService.save(testUser);}System.out.println("毫秒==>" + (System.currentTimeMillis() - l));
}# 插入10万条耗时:238040ms,大约4分钟

方案二:使用Mybatis-Plus的saveBatch

select * from oss_group where id_path like ‘0.1.%’;

@Test
public void testUserInsert() {long l = System.currentTimeMillis();List<TestUser> list = new ArrayList<>();for (int i = 0; i < 100000; i++) {TestUser testUser = new TestUser();testUser.setName("中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国");testUser.setAge(20);list.add(testUser);}testUserService.saveBatch(list);System.out.println("毫秒==>" + (System.currentTimeMillis() - l));
}# 插入耗时:62180ms,大约1分钟

这里先留下一张saveBatch的SQL日志截图,这里的日志是一个insert into语句,下面带了一千条数据(MP默认一千条一个批次),使用Mybatis Log插件查看还是单条的SQL

方案三:在方案二的基础上修改MySQL连接参数:rewriteBatchedStatements=true

# 与方案二测试代码相同
# 插入耗时:35260ms,大约半分钟

其SQL日志也如上方案二所示,MySQL Jdbc驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,直接造成较低的性能
Mysql连接配置链接

方案四:使用Mybatis-Plus提供的扩展插件:InsertBatchSomeColumn

@Test
public void testUserInsert() {long l = System.currentTimeMillis();List<TestUser> list = new ArrayList<>();for (int i = 0; i < 10000; i++) {TestUser testUser = new TestUser();testUser.setName("中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国中国");testUser.setAge(20);list.add(testUser);// 因为mysql的参数max_allowed_packet限制,所以这里程序改成单批1000条if(list.size() == 1000){testUserMapper.insertBatchSomeColumn(list);list.clear();}}System.out.println("毫秒==>" + (System.currentTimeMillis() - l));
}# 插入耗时:24410ms,大约24秒

再来看看此时控制台的SQL,与方案二的SQL有着明显的区别,这里是将批次插入的数据拼接在同一条SQL中,对于MySQL处理来说,这是真的批量新增

配置方式

// 1. 自定义SQL注入器
public class BatchSaveSqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass) {// 注意:保留mybatis-plus的自带方法List<AbstractMethod> methodList = super.getMethodList(mapperClass);methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));return methodList;}
}// 2. 实现自定义baseMapper
public interface BatchSaveBaseMapper<T> extends BaseMapper<T> {/*** 批量插入 仅适用于mysql** @param entityList*            实体列表* @return 影响行数*/Integer insertBatchSomeColumn(Collection<T> entityList);
}// 3. 注入插件
// 方式一
@Configuration
public class MybatisPlusConfig {/*** 分页插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));return paginationInterceptor;}/*** SQL注入器*/@Beanpublic BatchSaveSqlInjector easySqlInjector() {return new BatchSaveSqlInjector();}
}// 方式二
// 若项目有自定义SqlSessionFactory,也可在初始化时将自定义SQL注入器植入,参考下图MybatisPlusAutoConfiguration.sqlSessionFactory的做法

总结

插入10万数据耗时(秒)
mybatis-plus:save238
mybatis-plus的saveBatch:rewriteBatchedStatements=false62
mybatis-plus的saveBatch:rewriteBatchedStatements=true35
mybatis-plus扩展插件:InsertBatchSomeColumn24

相关文章:

Mybatis-Plus多种批量插入方案对比

背景 六月某日上线了一个日报表任务&#xff0c;因是第一次上线&#xff0c;故需要为历史所有日期都初始化一次报表数据 在执行过程中发现新增特别的慢&#xff1a;插入十万条左右的数据&#xff0c;SQL执行耗费高达三分多钟 因很早就听闻过mybatis-plus的[伪]批量新增的问题&…...

数据库面试

1. 简单介绍一下Spring中的事务管理。 答&#xff1a;事务就是对一系列的数据库操作&#xff08;比如将insert&#xff0c;delete&#xff0c;update&#xff0c;select多条sql语句&#xff09;作为一个整体执行&#xff0c;进行统一的提交或回滚操作&#xff0c;如果这组sql语…...

探索Web Components

title: 探索Web Components date: 2024/6/16 updated: 2024/6/16 author: cmdragon excerpt: 这篇文章介绍了Web Components技术&#xff0c;它允许开发者创建可复用、封装良好的自定义HTML元素&#xff0c;并直接在浏览器中运行&#xff0c;无需依赖外部库。通过组合HTML模…...

摄影师在人工智能竞赛中与机器较量并获胜

摄影师在人工智能竞赛中与机器较量并获胜 自从生成式人工智能出现以来&#xff0c;由来已久的人机大战显然呈现出一边倒的态势。但是有一位摄影师&#xff0c;一心想证明用人眼拍摄的照片是有道理的&#xff0c;他向算法驱动的竞争对手发起了挑战&#xff0c;并取得了胜利。 迈…...

CMU最新论文:机器人智慧流畅的躲避障碍物论文详细讲解

CMU华人博士生Tairan He最新论文&#xff1a;Agile But Safe: Learning Collision-Free High-Speed Legged Locomotion 代码开源&#xff1a;Code: https://github.com/LeCAR-Lab/ABS B站实际效果展示视频地址&#xff1a;bilibili效果地址 我会详细解读论文的内容,让我们开始吧…...

Spring中自定义注解进行类方法增强

说明 说到对类方法增强&#xff0c;第一时间想到自定义注解&#xff0c;通过aop切面进行实现。这是一种常用做法&#xff0c;但是在某些场景下&#xff0c;如开发公共组件&#xff0c;定义aop切面可能不是最优方案。以后通过原生aop方式&#xff0c;自定义注解&#xff0c;对类…...

TS:元组

问: 解释下什么是元组 回答: 元组&#xff08;Tuple&#xff09;是一种数据结构&#xff0c;类似于数组&#xff0c;但与数组不同的是&#xff0c;元组中的元素类型可以各不相同&#xff0c;且元组的长度是固定的。元组在许多编程语言中都有实现&#xff0c;包括 TypeScript…...

微服务 | Springboot整合Dubbo+Nacos实现RPC调用

官网&#xff1a;Apache Dubbo 随着互联网技术的飞速发展&#xff0c;越来越多的企业和开发者开始关注微服务架构。微服务架构可以将一个大型的应用拆分成多个独立、可扩展、可维护的小型服务&#xff0c;每个服务负责实现应用的一部分功能。这种架构方式可以提高开发效率&…...

读书的意义

...

第66集《摄大乘论》

请大家打开《讲义》第二二二页&#xff1a; 庚九、念(分二&#xff1a;辛一正念法身&#xff1b;辛二兼显净土) 辛一、正念法身(分二&#xff1a;壬一征&#xff1b;壬二释) 壬一、征 这个是讲到十门分别(二0三页)&#xff0c;分别清净法身的第九段&#xff0c;讲到念&…...

VMware 桥接网络突然无法上网

VMware 桥接网络突然无法上网 0. 问题1. 解决方法 0. 问题 昨天&#xff0c;VMware 桥接网络正常使用&#xff0c;今天突然无法上网。 1. 解决方法 打开VMware的虚拟网络编辑器&#xff0c;将桥接模式的网络从“自动”改成你要使用的网卡&#xff0c;问题解决。 完成&#…...

面试题——Redis

★1.简述一下缓存穿透,缓存击穿,缓存雪崩 ? 缓存穿透:大量恶意请求一个不存在的数据,使得压力绕过Redis缓存层打到数据库,造成数据库瘫痪 处理:①设置黑名单,维护一个可能存在也可能不存在的黑名单数据列表,对请求进行过滤(简单高效) ②布隆过滤器,会出现误删,且相对麻烦(不…...

Java——构造器(构造方法)和 this

一、什么是构造器 构造器&#xff08;Constructor&#xff09;是Java类的一种特殊方法&#xff0c;用于初始化对象的状态。构造器在创建对象时被调用&#xff0c;可以对对象的成员变量进行初始化。 我之前的文章《Java——类和对象-CSDN博客》中也提到了构造器。 二、构造器…...

MySQL-连接查询

049-内连接之等值连接 案例&#xff1a;查询每个员工所在的部门名称&#xff0c;要求显示员工名、部门名。 select e.ename, d.dname from emp e inner join dept d on e.deptnod.deptno;注意&#xff1a;inner可以省略 select e.ename, d.dname from emp e join dept d on…...

适合小白学习的项目1832javaERP管理系统之仓库采购管理Myeclipse开发mysql数据库servlet结构java编程计算机网页项目

一、源码特点 java erp管理系统之仓库采购管理是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了serlvet设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Mye…...

分布式技术导论 — 探索分析从起源到现今的巅峰之旅(分布式技术)

分析探索从起源到现今的巅峰之旅 背景介绍数据可伸缩性案例 计算可伸缩性案例 代价和权衡分布式的代价分布式的权衡权衡策略 分布式技术方向数据系统运算系统 分布式数据系统Partition&#xff08;分区&#xff09;Round-Robin&#xff08;轮询&#xff09;局限性 Range&#x…...

基于Python+OpenCV+SVM车牌识别系统(GUI界面)【W3】

简介&#xff1a; 随着交通管理的日益复杂化和智能化需求的增加&#xff0c;车牌识别系统在安防、智慧交通管理等领域中扮演着重要角色。传统的车牌识别系统主要基于图像处理和模式识别技术&#xff0c;随着计算机视觉技术的发展&#xff0c;基于Python、OpenCV和机器学习算法的…...

ansible.cfg forks参数

在Ansible的配置文件ansible.cfg中&#xff0c;forks参数是一个非常关键的设置&#xff0c;它控制了Ansible执行任务时的并发连接数&#xff0c;直接影响到Ansible执行 playbook 或 ad-hoc 命令时的速度和效率。 意义与作用 并发控制&#xff1a;当你使用Ansible来管理多台主…...

Web前端写随机抽奖:技术与创意的碰撞

Web前端写随机抽奖&#xff1a;技术与创意的碰撞 在Web前端的世界里&#xff0c;随机抽奖功能不仅是一种常见的交互元素&#xff0c;更是技术与创意的完美结合。下面&#xff0c;我们将从四个方面、五个方面、六个方面和七个方面&#xff0c;深入探讨Web前端实现随机抽奖的技术…...

Centos系统yum安装mysql数据库

安装之前需要将系统自带的mariadb-libs软件包删除。 检查是否存在mariadb-libs包。 yum list installed|grep mariadb-libs 删除mariadb-libs包 yum -y remove mariadb-libs 声明&#xff1a; 系统&#xff1a;CentOS-7-x86_64-DVD-2009 安装为最小化安装&#xff0c;没…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...