SpringBoot中六种批量更新Mysql 方式效率对比

本文主要是介绍SpringBoot中六种批量更新Mysql 方式效率对比,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

SpringBoot中六种批量更新Mysql 方式效率对比

先上结论吧,有空可以自测一下,数据量大时运行一次还时挺耗时的

效率比较

小数据量时6中批量更新效率不太明显,根据项目选择合适的即可,以1万条为准做个效率比较,效率从高到低一次排名如下

  1. replace intoON DUPLICATE KEY效率最高
  2. mybatis-plus 有取巧嫌疑,因为是分批批量更新,其他几种都是一次更新
  3. for循环凭借sql和JdbcTemplate相近,即使5万条,10万条效率也相近
  4. case when

然而有时候我们只能选择case when,因为replace intoON DUPLICATE KEY公司不一定让用,项目也不一定引入mybatis-plus,数据库url中也不一定有allowMultiQueries=true参数,算是一个兜底方案吧,不管用那种方式大数据量时都需要考虑分批

测试结构

环境信息:mysql-8.0.35-winx64,本地win 10

依次为测试次数-平均耗时-最小耗时-最大耗时,单位为毫秒

数据量forcase whenreplace intoON DUPLICATE KEYmybatis-plusJdbcTemplate
500100-61-41-1202100-66-57-426100-16-10-282100-15-10-293100-73-52-564100-87-59-1449
1000100-131-94-2018100-241-219-675100-28-18-376100-25-17-331100-117-98-599100-188-136-2397
5000100-852-735-8297100-11219-10365-13496100-95-83-569100-93-82-552100-618-517-1415100-1161-911-9334
1000010-3957-2370-1730410-45537-44465-48119100-191-171-762100-188-169-772100-1309-1085-5021100-3671-2563-31112
5000010-50106-34568-130651卡死不动100-1026-919-1868100-1062-945-1934100-8062-6711-20841100-48744-35482-191011
10000010-160170-106223-264434卡死不动10-2551-2292-368810-2503-2173-3579100-17205-14436-2488110-169771-110522-343278

总结

  1. sql语句for循环效率其实相当高的,因为它仅仅有一个循环体,只不过最后update语句比较多,量大了就有可能造成sql阻塞,同时在mysql的url上需要加上allowMultiQueries=true参数,即 jdbc:mysql://localhost:3306/mysqlTest?characterEncoding=utf-8&allowMultiQueries=true(公司项目不一定加,我们也不一定有权限加)。

  2. case when虽然最后只会有一条更新语句,但是xml中的循环体有点多,每一个case when 都要循环一遍list集合,所以大批量拼sql的时候会比较慢,所以效率问题严重。使用的时候建议分批插入(我们公司一直用的就是这种,但是必须分批)。

  3. duplicate key update可以看出来是最快的,但是公司一般都禁止使用replace into和INSERT INTO … ON DUPLICATE KEY UPDATE,这种sql有可能会造成数据丢失和主从上表的自增id值不一致。而且用这个更新时,记得一定要加上id,而且values()括号里面放的是数据库字段,不是java对象的属性字段

  4. 根据效率,安全方面综合考虑,选择适合的很重要。

数据库

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 方式效率对比的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/976891

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#实现一键批量合并PDF文档

《C#实现一键批量合并PDF文档》这篇文章主要为大家详细介绍了如何使用C#实现一键批量合并PDF文档功能,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言效果展示功能实现1、添加文件2、文件分组(书签)3、定义页码范围4、自定义显示5、定义页面尺寸6、PDF批量合并7、其他方法