02-MybatisPlus批量插入性能够吗?

2024-06-15 05:28

本文主要是介绍02-MybatisPlus批量插入性能够吗?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 前言

“不要用 mybatis-plus 的批量插入,它其实也是遍历插入,性能很差的”。真的吗?他们的立场如下:

  1. 遍历插入,反复创建。这是一个重量级操作,所以性能差。这里不用看源码也知道,因为这个和mybatis-plus没关系,而且我们现在使用SpringBoot,一般也用它的JDBC启动依赖。连接和连接池不是本文重点,总之这观点纯属无稽之谈,和不懂技术的领导说话一个德行
  2. 一条 insert 就一次网络IO,数量多了,这是个很可观且没必要的开销,所以性能差

2 show me源码!

对第2个观点,结合源码来看吧!

2.1 环境

① mybatis-plus 3.5.3.1

pom.xml:

② application.yml
Spring:# 使用默认的连接池库 datasource:url: "*****"username: "****"password: "****"

Service使用之处:

2.2 进入saveBatch

com.baomidou.mybatisplus.extension.service.IService#saveBatch(java.util.Collection)

会给我们这个批量操作开启事务(若是期望插入一条就成功一条,该批量方法就不适用);

且有限制提交数量,默认1000。

来到ServiceImpl实现类:

可见,MP批量插入是一条条插入的,但是这个一次次的遍历是真的发送给MySQL了吗?。只要记得这里有一个钩子,后面会回调回来执行。

/*** 获取mapperStatementId** @param sqlMethod 方法名* @return 命名id* @since 3.4.0*/
protected String getSqlStatement(SqlMethod sqlMethod) {return SqlHelper.getSqlStatement(mapperClass, sqlMethod);
}/*** 执行批量操作** @param list      数据集合* @param batchSize 批量大小* @param consumer  执行方法* @param <E>       泛型* @return 操作结果* @since 3.3.1*/
protected <E> boolean executeBatch(Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {return SqlHelper.executeBatch(this.entityClass, this.log, list, batchSize, consumer);
}
3 SqlHelper#executeBatch(Class<?>, Log, Collection, int, BiConsumer<SqlSession,E>)
com.baomidou.mybatisplus.extension.toolkit.SqlHelper#executeBatch(java.lang.Class<?>, org.apache.ibatis.logging.Log, java.util.Collection, int, java.util.function.BiConsumer<org.apache.ibatis.session.SqlSession,E>)
/*** 执行批量操作** @param entityClass 实体类* @param log         日志对象* @param list        数据集合* @param batchSize   批次大小* @param consumer    consumer* @param <E>         T* @return 操作结果* @since 3.4.0*/
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {Assert.isFalse(batchSize < 1, "batchSize must not be less than one");return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, sqlSession -> {int size = list.size();int idxLimit = Math.min(batchSize, size);int i = 1;for (E element : list) {consumer.accept(sqlSession, element);if (i == idxLimit) {sqlSession.flushStatements();idxLimit = Math.min(idxLimit + batchSize, size);}i++;}});
}

sqlSession从哪来的?看executeBatch。

4 SqlHelper#executeBatch(Class<?> entityClass, Log log, Consumer consumer)
com.baomidou.mybatisplus.extension.toolkit.SqlHelper#executeBatch(java.lang.Class<?>, org.apache.ibatis.logging.Log, java.util.function.Consumer<org.apache.ibatis.session.SqlSession>)
public static boolean executeBatch(Class<?> entityClass, Log log, Consumer<SqlSession> consumer) {SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);try {consumer.accept(sqlSession);//非事务情况下,强制commit。sqlSession.commit(!transaction);}
}

结合前面代码,这里是到了1000(默认1000,并且我批量保存的list超过1000),就会开启会话,将内存的SQL全部刷到MySQL,然后回去继续遍历。

总结

MP批量插入虽然是遍历插入,但不是一个insert就一次IO,而是打包了一次发送一批,所以性能没太大问题。但不是鼓励大家都用这批量插入,实际工作有更多要求,有时简单的批量插入没法满足。还是看实际情况决定。

扩展

如果使用mybatis-plus 3.4+ 版本,并且连接的是 MySQL 8.0 或更高版本的数据库,那么 mybatis-plus将会自动利用MySQL 8.0 的原生批量插入功能来执行批量插入操作。

具体实现的关键是在mybatis-plus的底层使用了mybatis-plus的批量新增方法时,mybatis-plus会将待插入的对象列表传递给底层的。

注意确保以下条件满足才能利用:

使用 MySQL 8.0 或更高版本的数据库

使用兼容 MySQL 8.0 的 JDBC 驱动程序(如 mysql-connector-java 版本 8.0 或更高)

使用 mybatis-plus 3.4+ 版本

参考:https://www.jianshu.com/p/a387879ccb97

这篇关于02-MybatisPlus批量插入性能够吗?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

MybatisPlus service接口功能介绍

《MybatisPlusservice接口功能介绍》:本文主要介绍MybatisPlusservice接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录Service接口基本用法进阶用法总结:Lambda方法Service接口基本用法MyBATisP

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

Java如何从Redis中批量读取数据

《Java如何从Redis中批量读取数据》:本文主要介绍Java如何从Redis中批量读取数据的情况,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一.背景概述二.分析与实现三.发现问题与屡次改进3.1.QPS过高而且波动很大3.2.程序中断,抛异常3.3.内存消

解决mysql插入数据锁等待超时报错:Lock wait timeout exceeded;try restarting transaction

《解决mysql插入数据锁等待超时报错:Lockwaittimeoutexceeded;tryrestartingtransaction》:本文主要介绍解决mysql插入数据锁等待超时报... 目录报错信息解决办法1、数据库中执行如下sql2、再到 INNODB_TRX 事务表中查看总结报错信息Lock

MySQL数据库实现批量表分区完整示例

《MySQL数据库实现批量表分区完整示例》通俗地讲表分区是将一大表,根据条件分割成若干个小表,:本文主要介绍MySQL数据库实现批量表分区的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考... 目录一、表分区条件二、常规表和分区表的区别三、表分区的创建四、将既有表转换分区表脚本五、批量转换表为分区

Oracle 通过 ROWID 批量更新表的方法

《Oracle通过ROWID批量更新表的方法》在Oracle数据库中,使用ROWID进行批量更新是一种高效的更新方法,因为它直接定位到物理行位置,避免了通过索引查找的开销,下面给大家介绍Orac... 目录oracle 通过 ROWID 批量更新表ROWID 基本概念性能优化建议性能UoTrFPH优化建议注

SpringBoot整合mybatisPlus实现批量插入并获取ID详解

《SpringBoot整合mybatisPlus实现批量插入并获取ID详解》这篇文章主要为大家详细介绍了SpringBoot如何整合mybatisPlus实现批量插入并获取ID,文中的示例代码讲解详细... 目录【1】saveBATch(一万条数据总耗时:2478ms)【2】集合方式foreach(一万条数

Python实现AVIF图片与其他图片格式间的批量转换

《Python实现AVIF图片与其他图片格式间的批量转换》这篇文章主要为大家详细介绍了如何使用Pillow库实现AVIF与其他格式的相互转换,即将AVIF转换为常见的格式,比如JPG或PNG,需要的小... 目录环境配置1.将单个 AVIF 图片转换为 JPG 和 PNG2.批量转换目录下所有 AVIF 图

详解如何通过Python批量转换图片为PDF

《详解如何通过Python批量转换图片为PDF》:本文主要介绍如何基于Python+Tkinter开发的图片批量转PDF工具,可以支持批量添加图片,拖拽等操作,感兴趣的小伙伴可以参考一下... 目录1. 概述2. 功能亮点2.1 主要功能2.2 界面设计3. 使用指南3.1 运行环境3.2 使用步骤4. 核

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE