SpringBoot中六种批量更新Mysql 方式效率对比
SpringBoot中六种批量更新Mysql 方式效率对比
先上结论吧,有空可以自测一下,数据量大时运行一次还时挺耗时的
效率比较
小数据量时6中批量更新效率不太明显,根据项目选择合适的即可,以1万条为准做个效率比较,效率从高到低一次排名如下
replace into和ON DUPLICATE KEY效率最高mybatis-plus有取巧嫌疑,因为是分批批量更新,其他几种都是一次更新- for循环凭借sql和JdbcTemplate相近,即使5万条,10万条效率也相近
- case when
然而有时候我们只能选择case when,因为replace into和ON DUPLICATE KEY公司不一定让用,项目也不一定引入mybatis-plus,数据库url中也不一定有allowMultiQueries=true参数,算是一个兜底方案吧,不管用那种方式大数据量时都需要考虑分批
测试结构
环境信息:mysql-8.0.35-winx64,本地win 10
依次为测试次数-平均耗时-最小耗时-最大耗时,单位为毫秒
| 数据量 | for | case when | replace into | ON DUPLICATE KEY | mybatis-plus | JdbcTemplate |
|---|---|---|---|---|---|---|
| 500 | 100-61-41-1202 | 100-66-57-426 | 100-16-10-282 | 100-15-10-293 | 100-73-52-564 | 100-87-59-1449 |
| 1000 | 100-131-94-2018 | 100-241-219-675 | 100-28-18-376 | 100-25-17-331 | 100-117-98-599 | 100-188-136-2397 |
| 5000 | 100-852-735-8297 | 100-11219-10365-13496 | 100-95-83-569 | 100-93-82-552 | 100-618-517-1415 | 100-1161-911-9334 |
| 10000 | 10-3957-2370-17304 | 10-45537-44465-48119 | 100-191-171-762 | 100-188-169-772 | 100-1309-1085-5021 | 100-3671-2563-31112 |
| 50000 | 10-50106-34568-130651 | 卡死不动 | 100-1026-919-1868 | 100-1062-945-1934 | 100-8062-6711-20841 | 100-48744-35482-191011 |
| 100000 | 10-160170-106223-264434 | 卡死不动 | 10-2551-2292-3688 | 10-2503-2173-3579 | 100-17205-14436-24881 | 10-169771-110522-343278 |
总结
-
sql语句for循环效率其实相当高的,因为它仅仅有一个循环体,只不过最后update语句比较多,量大了就有可能造成sql阻塞,同时在mysql的url上需要加上allowMultiQueries=true参数,即 jdbc:mysql://localhost:3306/mysqlTest?characterEncoding=utf-8&allowMultiQueries=true(公司项目不一定加,我们也不一定有权限加)。
-
case when虽然最后只会有一条更新语句,但是xml中的循环体有点多,每一个case when 都要循环一遍list集合,所以大批量拼sql的时候会比较慢,所以效率问题严重。使用的时候建议分批插入(我们公司一直用的就是这种,但是必须分批)。
-
duplicate key update可以看出来是最快的,但是公司一般都禁止使用replace into和INSERT INTO … ON DUPLICATE KEY UPDATE,这种sql有可能会造成数据丢失和主从上表的自增id值不一致。而且用这个更新时,记得一定要加上id,而且values()括号里面放的是数据库字段,不是java对象的属性字段
-
根据效率,安全方面综合考虑,选择适合的很重要。
数据库
CREATE TABLE `people` (`id` bigint(8) NOT NULL AUTO_INCREMENT,`first_name` varchar(50) NOT NULL DEFAULT '',`last_name` varchar(50) NOT NULL DEFAULT '',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
初始化测试数据
//初始化10w数据
@Test
void init10wData() {for (int i = 0; i < 100000; i++) {People people = new People();people.setFirstName(UUID.randomUUID().toString());people.setLastName(UUID.randomUUID().toString());peopleDAO.insert(people);}
}
批量修改方案
第一种 for
<!-- 批量更新第一种方法,通过接收传进来的参数list进行循环组装sql -->
<update id="updateBatch" parameterType="java.util.List"><foreach collection="list" item="item" index="index" open="" close="" separator=";">update people<set><if test="item.firstName != null">first_name = #{item.firstName,jdbcType=VARCHAR},</if><if test="item.lastName != null">last_name = #{item.lastName,jdbcType=VARCHAR},</if></set>where id = #{item.id,jdbcType=BIGINT}</foreach>
</update>
第二种 case when
<!-- 批量更新第二种方法,通过 case when语句变相的进行批量更新 -->
<update id="updateBatch2" parameterType="java.util.List">update people<set><foreach collection="list" item="item"><if test="item.firstName != null">first_name = case when id = #{item.id} then #{item.firstName} else first_name end,</if><if test="item.lastName != null">last_name = case when id = #{item.id} then #{item.lastName} else last_name end,</if></foreach></set>where id in<foreach collection="list" item="item" separator="," open="(" close=")">#{item.id}</foreach>
</update>
第三种 replace into
<!-- 批量更新第三种方法,通过 replace into -->
<update id="updateBatch3" parameterType="java.util.List">replace into people(id,first_name,last_name) values<foreach collection="list" index="index" item="item" separator=",">(#{item.id},#{item.firstName},#{item.lastName})</foreach>
</update>
第四种 ON DUPLICATE KEY UPDATE
<!-- 批量更新第四种方法,通过 duplicate key update -->
<update id="updateBatch4" parameterType="java.util.List">insert into people(id,first_name,last_name) values<foreach collection="list" index="index" item="item" separator=",">(#{item.id},#{item.firstName},#{item.lastName})</foreach>ON DUPLICATE KEY UPDATEid=values(id),first_name=values(first_name),last_name=values(last_name)
</update>
第五种mybatis-plus提供的的批量更新
default boolean updateBatchById(Collection<T> entityList) {return this.updateBatchById(entityList, 1000);
}
boolean updateBatchById(Collection<T> entityList, int batchSize);
mybatis-plus提供的批量更新是分批批量更新,默认每批1000条,可以指定分批的条数,每批执行完成后提交一下事务,不加@Transactional可能会出现第一批更新成功了,第二批更新失败了的情况.
第六种JdbcTemplate提供的批量更新
测试代码
/*** PeopleDAO继承基类*/
@Mapper
@Repository
public interface PeopleDAO extends MyBatisBaseDao<People, Long> {void updateBatch(@Param("list") List<People> list);void updateBatch2(List<People> list);void updateBatch3(List<People> list);void updateBatch4(List<People> list);
}
@SpringBootTest
class PeopleMapperTest {@ResourcePeopleMapper peopleMapper;@ResourcePeopleService peopleService;@ResourceJdbcTemplate jdbcTemplate;@Testvoid init10wData() {for (int i = 0; i < 100000; i++) {People people = new People();people.setFirstName(UUID.randomUUID().toString());people.setLastName(UUID.randomUUID().toString());peopleMapper.insert(people);}}@Testvoid updateBatch() {List<People> list = new ArrayList();int loop = 100;int count = 5000;Long maxCost = 0L;//最长耗时Long minCost = Long.valueOf(Integer.MAX_VALUE);//最短耗时for (int j = 0; j < count; j++) {People people = new People();people.setId(ThreadLocalRandom.current().nextInt(0, 100000));people.setFirstName(UUID.randomUUID().toString());people.setLastName(UUID.randomUUID().toString());list.add(people);}Long startTime = System.currentTimeMillis();for (int i = 0; i < loop; i++) {Long curStartTime = System.currentTimeMillis();// peopleMapper.updateBatch4(list);// peopleService.updateBatchById(list);jdbcTemplateBatchUpdate(list);Long curCostTime = System.currentTimeMillis() - curStartTime;if (maxCost < curCostTime) {maxCost = curCostTime;}if (minCost > curCostTime) {minCost = curCostTime;}}System.out.println(loop + "-" + (System.currentTimeMillis() - startTime) / loop + "-" + minCost + "-" + maxCost );}private void jdbcTemplateBatchUpdate (List<People> list){String sql = "update people set first_name=?,last_name=? where id = ?";List<Object[]> params = list.stream().map(item -> new Object[]{item.getFirstName(), item.getLastName(), item.getId()}).collect(Collectors.toList());jdbcTemplate.batchUpdate(sql,params);}
}
参考文章:
mybatis批量更新数据三种方法效率对比 https://blog.csdn.net/q957967519/article/details/88669552
MySql中4种批量更新的方法 https://blog.csdn.net/weixin_42290280/article/details/89384741
Mysql 批量修改四种方式效率对比(一)https://blog.csdn.net/zk673820543/article/details/106579809/
相关文章:
SpringBoot中六种批量更新Mysql 方式效率对比
SpringBoot中六种批量更新Mysql 方式效率对比 先上结论吧,有空可以自测一下,数据量大时运行一次还时挺耗时的 效率比较 小数据量时6中批量更新效率不太明显,根据项目选择合适的即可,以1万条为准做个效率比较,效率从高到低一次排名如下 replace into和ON DUPLICATE KEY效率最…...
【SpringBoot】SpringBoot整合jasypt进行重要数据加密
📝个人主页:哈__ 期待您的关注 目录 📕jasypt简介 🔥SpringBoot使用jasypt 📂创建我需要的数据库文件 📕引入依赖 🔓配置数据库文件(先不进行加密) 🌙创…...
【Go语言入门学习笔记】Part1.梦开始的地方
一、前言 经过一系列的学习,终于有时间来学习一些新的语言,Go语言在现在还是比较时髦的,多一个技能总比不多的好,故有时间来学一下。 二、配置环境 按照网络中已有的配置方法配置好,本人采用了Jetbrain的Goland&#…...
数据特征降维 | 主成分分析(PCA)附Python代码
主成分分析(Principal Component Analysis,PCA)是一种常用的数据降维技术和探索性数据分析方法,用于从高维数据中提取出最重要的特征并进行可视化。 PCA的基本思想是通过线性变换将原始数据投影到新的坐标系上,使得投影后的数据具有最大的方差。这些新的坐标轴称为主成分…...
当服务实例出现故障时,Nacos如何处理?
当服务实例出现故障时,Nacos的应对策略 在微服务架构日益盛行的今天,服务之间的稳定性与可靠性成为了我们架构师们不得不面对的重要课题。尤其是在面对服务实例出现故障时,如何确保整个系统的稳定运行,成为了我们首要考虑的问题。…...
遥感数据集制作(Potsdam数据集为例):TIF图像转JPG,TIF标签转PNG,图像重叠裁剪
文章目录 TIF图像转JPGTIF标签转PNG图像重叠裁剪图像重命名数据集转COCO格式数据集转VOC格式 遥感图像不同于一般的自然图像,由于波段数量、图像位深度等原因,TIF图像数据不能使用简单的格式转换方法。本文以Potsdam数据集为例,制作能够直接用…...
根据web访问日志,封禁请求量异常的IP,如IP在半小 时后恢复正常则解除封禁
在网络安全日益受到重视的今天,如何有效防范恶意流量和攻击成为了每个网站管理员必须面对的问题。恶意流量不仅会影响网站的正常运行,还可能导致服务器崩溃,给网站带来不可估量的损失。为了应对这一问题,我们特别推出了一款实用的…...
2.go语言初始(二)
本篇博客涉及到go 的基础数据类型、 go 语言中的运算符、转义字符、格式化输出、字符串操作 go 语言中的运算符 在 go 语言中,基本数据类型主要包括以下几类:整数类型、浮点数类型、复数类型、布尔类型、字符串类型、字节类型(byte…...
MQTT对比HTTP
吞吐量:根据3G网络的测量结果,MQTT的吞吐量比HTTP快93倍。这意味着在相同的网络条件下,MQTT能够更有效地传输数据,从而在处理大量数据或实时数据传输时具有更高的效率。架构与模式:MQTT基于发布/订阅模型,提…...
暴力数据结构之二叉树(堆的相关知识)
1. 堆的基本了解 堆(heap)是计算机科学中一种特殊的数据结构,通常被视为一个完全二叉树,并且可以用数组来存储。堆的主要应用是在一组变化频繁(增删查改的频率较高)的数据集中查找最值。堆分为大根堆和小根…...
死锁调试技巧:工作线程和用户界面线程
有人碰到了一个死锁问题,找到我们想请我们看看,这个是关于应用程序用户界面相关的死锁问题。 我也不清楚他为什么会找上我们,可能是因为我们经常会和窗口管理器打交道吧。 下面,我们来看看死锁的两个线程。 >> 请移步至 …...
蓝桥杯-外卖店优先级(简单写法)
“饱了么”外卖系统中维护着 N 家外卖店,编号 1∼N。 每家外卖店都有一个优先级,初始时 (0 时刻) 优先级都为 0。 每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减到 0;而如果外卖店有订…...
VueRouter使用总结
VueRouter 是 Vue.js 的官方路由管理器,用于构建单页面应用(SPA)。在使用 VueRouter 时,开发者可以定义路由映射规则,并在 Vue 组件中通过编程式导航或声明式导航的方式控制页面的跳转和展示。以下是 VueRouter 使用的…...
Flink checkpoint 源码分析- Checkpoint snapshot 处理流程
背景 在上一篇博客中我们分析了代码中barrier的是如何流动传递的。Flink checkpoint 源码分析- Checkpoint barrier 传递源码分析-CSDN博客 最后跟踪到了代码org.apache.flink.streaming.runtime.io.checkpointing.CheckpointedInputGate#handleEvent 现在我们接着跟踪相应…...
Leaflet.canvaslabel在Ajax异步请求时bindPopup无效的解决办法
目录 前言 一、场景重现 1、遇到问题的代码 2、问题排查 二、通过实验验证猜想 1、排查LayerGroup和FeatureGroup 2、排查Leaflet.canvaslabel.js 三、柳暗花明又一村 1、点聚类的办法 2、歪打正着 总结 前言 在上一篇博客中介绍了基于SpringBoot的全国风景区WebGIS按…...
Go 处理错误
如果你习惯了 try catch 这样的语法后,会觉得处理错误真简单,然后你再来接触 Go 的错误异常,你会发现他好复杂啊,怎么到处都是 error,到处都需要处理 error。 首先咱们需要知道 Go 语言里面有个约定,就是一…...
python读取excel数据写入mysql
概述 业务中有时会需要解析excel中的数据,按照要求处理后,写入到db中; 用python处理这个正好简便快捷 demo 没有依赖就 pip install pymysql一下 import pymysql from pymysql.converters import escape_string from openpyxl import loa…...
flutter日期选择器仅选择年、月
引入包:flutter_datetime_picker: 1.5.0 封装 import package:flutter/cupertino.dart; import package:flutter/material.dart; import package:flutter_datetime_picker/flutter_datetime_picker.dart;class ATuiDateTimePicker {static Future<DateTime> …...
素数筛详解c++
一、埃式筛法 代码 二、线性筛法(欧拉筛法) 主要的思想就是一个质数的倍数(倍数为1除外)肯定是合数,那么我们利用这个质数算出合数,然后划掉这个合数,下次就可以不用判断它是不是质数,节省了大量的时间。 …...
【Python超详细的学习笔记】Python超详细的学习笔记,涉及多个领域,是个很不错的笔记
获取笔记链接 Python超详细的学习笔记 一,逆向加密模块 1,Python中运行JS代码 1.1 解决中文乱码或者报错问题 import subprocess from functools import partial subprocess.Popen partial(subprocess.Popen, encodingutf-8) import execjs1.2 常用…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
python打卡第47天
昨天代码中注意力热图的部分顺移至今天 知识点回顾: 热力图 作业:对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图,展示模…...
构建Docker镜像的Dockerfile文件详解
文章目录 前言Dockerfile 案例docker build1. 基本构建2. 指定 Dockerfile 路径3. 设置构建时变量4. 不使用缓存5. 删除中间容器6. 拉取最新基础镜像7. 静默输出完整示例 docker runDockerFile 入门syntax指定构造器FROM基础镜像RUN命令注释COPY复制ENV设置环境变量EXPOSE暴露端…...
解密鸿蒙系统的隐私护城河:从权限动态管控到生物数据加密的全链路防护
摘要 本文以健康管理应用为例,展示鸿蒙系统如何通过细粒度权限控制、动态权限授予、数据隔离和加密存储四大核心机制,实现复杂场景下的用户隐私保护。我们将通过完整的权限请求流程和敏感数据处理代码,演示鸿蒙系统如何平衡功能需求与隐私安…...
