MyBatis-plus的批量插入方式对比分析
MyBatis-plus的批量插入方式对比分析
【摘要】Mybatis批量插入一直是开发者重点关注的问题,本文列举了Mybatis的五种插入方式进行对比分析,验证了五种批量插入的方式的优先级。
1 准备工作
1.1 新建spring项目
略。
1.2 导入pom.xml依赖
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency><!--Mybatis依赖-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
</dependency><!--Mybatis-Plus依赖-->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
1.3 配置yml文件
server:port: 8080spring:datasource:username: mysql用户名password: mysql密码url: jdbc:mysql://localhost:3306/数据库名字?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTCdriver-class-name: com.mysql.cj.jdbc.Drivermybatis:mapper-locations: classpath:mapping/*.xml
1.4 创建插入模型
@Data
public class User {private int id;private String username;private String password;
}
2 测试
2.1 Mybatis利用For循环批量插入
1、编写UserService服务类,测试一万条数据的耗时情况:
@Service
public class UserService {@Resourceprivate UserMapper userMapper;public void InsertUsers(){long start = System.currentTimeMillis();for(int i = 0 ;i < 10000; i++) {User user = new User();user.setUsername("name" + i);user.setPassword("password" + i);userMapper.insertUsers(user);}long end = System.currentTimeMillis();System.out.println("一万条数据总耗时:" + (end-start) + "ms" );}}
2、编写UserMapper接口
@Mapper
public interface UserMapper {Integer insertUsers(User user);
}
3、编写UserMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ithuang.demo.mapper.UserMapper"><insert id="insertUsers">INSERT INTO user (username, password)VALUES(#{username}, #{password})</insert>
</mapper>
4、进行单元测试
@SpringBootTest
class DemoApplicationTests {@Resourceprivate UserService userService;@Testpublic void insert(){userService.InsertUsers();}
}
5、输出结果
一万条数据耗时26348ms
2.2 MyBatis的手动批量提交
1、其他保持不变,Service层作稍微的变化
@Service
public class UserService {@Resourceprivate UserMapper userMapper;@Resourceprivate SqlSessionTemplate sqlSessionTemplate;public void InsertUsers(){//关闭自动提交SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);UserMapper userMapper = sqlSession.getMapper(UserMapper.class);long start = System.currentTimeMillis();for(int i = 0 ;i < 10000; i++) {User user = new User();user.setUsername("name" + i);user.setPassword("password" + i);userMapper.insertUsers(user);}sqlSession.commit();long end = System.currentTimeMillis();System.out.println("一万条数据总耗时:" + (end-start) + "ms" );}
}
2、结果输出
一万条数据总耗时:24516ms。
2.3 Mybatis以集合方式批量新增
1、编写UserService服务类
@Service
public class UserService {@Resourceprivate UserMapper userMapper;public void InsertUsers(){long start = System.currentTimeMillis();List<User> userList = new ArrayList<>();User user;for(int i = 0 ;i < 10000; i++) {user = new User();user.setUsername("name" + i);user.setPassword("password" + i);userList.add(user);}userMapper.insertUsers(userList);long end = System.currentTimeMillis();System.out.println("一万条数据总耗时:" + (end-start) + "ms" );}
}
2、编写UserMapper接口
@Mapper
public interface UserMapper {Integer insertUsers(List<User> userList);
}
3、编写UserMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ithuang.demo.mapper.UserMapper"><insert id="insertUsers">INSERT INTO user (username, password)VALUES<foreach collection ="userList" item="user" separator =",">(#{user.username}, #{user.password})</foreach></insert>
</mapper>
4、输出结果
一万条数据总耗时:521ms
2.4 MyBatis-Plus提供的SaveBatch方法
1、编写UserService服务
@Service
public class UserService extends ServiceImpl<UserMapper, User> implements IService<User> {public void InsertUsers(){long start = System.currentTimeMillis();List<User> userList = new ArrayList<>();User user;for(int i = 0 ;i < 10000; i++) {user = new User();user.setUsername("name" + i);user.setPassword("password" + i);userList.add(user);}saveBatch(userList);long end = System.currentTimeMillis();System.out.println("一万条数据总耗时:" + (end-start) + "ms" );}
}
2、编写UserMapper接口
@Mapper
public interface UserMapper extends BaseMapper<User> {}
3、单元测试结果
一万条数据总耗时:24674ms
2.5 MyBatis-Plus提供的InsertBatchSomeColumn方法
1、编写EasySqlInjector 自定义类
public class EasySqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {// 注意:此SQL注入器继承了DefaultSqlInjector(默认注入器),调用了DefaultSqlInjector的getMethodList方法,保留了mybatis-plus的自带方法List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));return methodList;}}
2、定义核心配置类注入此Bean
@Configuration
public class MybatisPlusConfig {
@Bean
public EasySqlInjector sqlInjector() {return new EasySqlInjector();
}
}
3、编写UserService服务类
public class UserService{@Resourceprivate UserMapper userMapper;public void InsertUsers(){long start = System.currentTimeMillis();List<User> userList = new ArrayList<>();User user;for(int i = 0 ;i < 10000; i++) {user = new User();user.setUsername("name" + i);user.setPassword("password" + i);userList.add(user);}userMapper.insertBatchSomeColumn(userList);long end = System.currentTimeMillis();System.out.println("一万条数据总耗时:" + (end-start) + "ms" );}
}
4、编写EasyBaseMapper接口
public interface EasyBaseMapper<T> extends BaseMapper<T> {/*** 批量插入 仅适用于mysql** @param entityList 实体列表* @return 影响行数*/Integer insertBatchSomeColumn(Collection<T> entityList);
}
5、编写UserMapper接口
@Mapper
public interface UserMapper<T> extends EasyBaseMapper<User> {}
6、单元测试结果
一万条数据总耗时:575ms
2.6 JDBC原生的批量插入
1、编写JDBC池化工具类
public class JDBCDruidUtils {private static DataSource dataSource;private static Connection conn;/*创建数据Properties集合对象加载加载配置文件*/static {Properties pro = new Properties();//加载数据库连接池对象try {//获取数据库连接池对象pro.load(JDBCDruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));dataSource = DruidDataSourceFactory.createDataSource(pro);} catch (Exception e) {e.printStackTrace();}}/*获取连接*/public static Connection getConnection() throws SQLException {return dataSource.getConnection();}/*** 关闭conn,和 statement独对象资源** @param connection* @param statement* @MethodName: close* @return: void*/public static void close(Connection connection, Statement statement) {if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}}/*** 关闭 conn , statement 和resultset三个对象资源** @param connection* @param statement* @param resultSet* @MethodName: close* @return: void*/public static void close(Connection connection, Statement statement, ResultSet resultSet) {close(connection, statement);if (resultSet != null) {try {resultSet.close();} catch (SQLException e) { e.printStackTrace();}}}/*获取连接池对象*/public static DataSource getDataSource() {return dataSource;}
}
# druid.properties配置
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/数据库?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username=用户名
password=密码
initialSize=10
maxActive=50
maxWait=60000
2、编写UserService服务类
public void InsertUsersByJdbc() {long start = System.currentTimeMillis();Connection connection = null;PreparedStatement ps = null;try {connection = JDBCDruidUtils.getConnection();//控制事务:默认不提交connection.setAutoCommit(false);String sql = "INSERT INTO user (username, password) VALUES (?, ?)";ps = connection.prepareStatement(sql);User user;for (int i = 0; i < 1000000; i++) {user = new User();user.setUsername("name" + i);user.setPassword("password" + i);ps.setString(1, user.getUsername());ps.setString(2, user.getPassword());//将一组参数添加到此 PreparedStatement 对象的批处理命令中。ps.addBatch();}//执行批处理ps.executeBatch();//手动提交事务connection.commit();} catch (SQLException e) {throw new RuntimeException(e);} finally {JDBCDruidUtils.close(connection, ps);}long end = System.currentTimeMillis();System.out.println("一万条数据总耗时:" + (end - start) + "ms");}
3、输出结果
1万数据总耗时19000ms。
3 总结
大量数据的场景下性能对比:InsertBatchSomeColumn>自定义xml以集合的方式>Jdbc原生>SaveBatch>手动for循环批量>自动for循环批量。
网上很多人都说JDBC原生性能很好,但是我发现其非常差,有可能是我使用的是mybatis-plus依赖,如果这是推论正确,那就可以证明mybatis-plus在mybatis的基础上不仅增强了功能也增强了性能。所以可以得出结论:开发中用mybatis-plus是没有错的,如果想提高性能,只能实施其他方案,比如分库分表,千万别想着JDBC原生性能更好。
相关文章:
MyBatis-plus的批量插入方式对比分析
MyBatis-plus的批量插入方式对比分析 【摘要】Mybatis批量插入一直是开发者重点关注的问题,本文列举了Mybatis的五种插入方式进行对比分析,验证了五种批量插入的方式的优先级。 1 准备工作 1.1 新建spring项目 略。 1.2 导入pom.xml依赖 <depende…...
【系分论文】论软件开发模型及应用
目录 论题论题介绍论文要点理论素材准备范文摘要正文 论文补充知识 论题 论软件开发模型及应用 论题介绍 软件开发模型( Software Development Model)是指软件开发全部过程、活动和任务的结构框架。软件开发过程包括需求、设计、编码和测试等阶段&…...
渗透测试--5.3.使用john破解密码
前言 由于Linux是Internet最流行的服务器操作系统,因此它的安全性备受关注。这种安全主要靠口令实现。 Linux使用一个单向函数crypt()来加密用户口令。单向函数crypt()从数学原理上保证了从加密的密文得到加密前的明…...
Go中的变量类型
Go中的变量类型 1.为什么要使用变量 变量其实指定的是一段内存地址,根据这个内存地址可以找到我们需要找到的东西。 2.变量类型 变量的功能就是用来存储数据的,根据不同的数据类型可以存储不同的数据。常见的变量的类型 整型、浮点型、布尔型等。变…...
基于STM32的NRF24L01 2.4G通讯模块的驱动实验(HAL库)
前言:本文为手把手教学NRF24L01 2.4G通讯模块的驱动实验,本教程的 MCU 采用STM32F103ZET6与STM32F103C8T6,彼此进行互相通讯。通过 CubeMX 软件配置 SPI 协议驱动NRF24L01 2.4G通讯模块(HAL库)。NRF24L01 2.4G是嵌入式…...
DJ5-3 多路访问链路和协议
目录 一、网络链路 二、广播信道要解决问题 三、多路访问协议 1、基本介绍 2、多路访问协议的类型(3) 四、信道划分协议 1、时分多路访问 TDMA 2、频分多路访问 FDMA 3、码分多路访问 CDMA(略) 五、随机访问协议 1、纯…...
技术领导力?
作品集(Portfolio)会比简历(Resume)更有参考意义。 怎么才算有技术领导力? 1) 能够发现问题,并能够提供解决问题的思路和方案,并能比较方案的优缺点。 2) 能用更简洁有效的方式解决问题。 3…...
计算机的基本工作原理
参考资料: L-1.6: Common Bus system| How basic computer works - YouTube 准备好内存单元、不同类型的寄存器,内存和寄存器、寄存器和寄存器之间都是通过总线连接(假设是直接把数据总线、控制总线、地址总线变成一条总线)。 使用多路复用器实现的总线&…...
【论文简述】Cross-Attentional Flow Transformer for Robust Optical Flow(CVPR 2022)
一、论文简述 1. 第一作者:Xiuchao Sui、Shaohua Li 2. 发表年份:2021 3. 发表期刊:arxiv 4. 关键词:光流、Transformer、自注意力、交叉注意力、相关体 5. 探索动机:由于卷积的局部性和刚性权重,有限…...
【JAVA】Java中方法的使用,理解方法重载和递归
目录 1.方法的概念及使用 1.1什么是方法 1.2方法的定义 1.3方法调用的执行过程 1.4实参和形参 2.方法重载 2.1为什么需要使用方法重载 2.2什么是方法重载 3.递归 3.1什么是递归 3.2递归执行的过程 3.3递归的使用 1.方法的概念及使用 1.1什么是方法 方法就是一个代…...
高级网络计算模式复习
P2P 对等网络(Peer-to-Peer Networks)是分布式系统和计算机网络相结合的产物,在应用领域和学术界获得了广泛的重视和成功,被称为“改变Internet的一代网络技术”。 peer指网络结点,在行为上是自由的——任意加入、退…...
【笔试强训选择题】Day15.习题(错题)解析
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:笔试强训选择题 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!! 文章目录 前言 一、…...
图论专题(一)
图论专题(一) 参考文献 BFS和DFS的直观解释 https://blog.csdn.net/c406495762/article/details/117307841Leetcode岛屿问题系列分析 https://blog.csdn.net/qq_39144436/article/details/124173504多源广度优先 https://blog.csdn.net/peko1/article/details/121989497拓扑排…...
新星计划2023【网络应用领域基础】————————Day4
常见的网络基础介绍 前言 我们学习了一些基础的网络协议,以及子网掩码和vlan,同时也做了个简单的单臂路由实验 这篇文章我将仔细的讲解单臂路由的应用和交换机二层接口类型,以及wireshark的教程。 一,交换机二层接口 交换机的二…...
[CTF/网络安全] 攻防世界 view_source 解题详析
[CTF/网络安全] 攻防世界 view_source 解题详析 查看页面源代码方式归类总结 题目描述:X老师让小宁同学查看一个网页的源代码,但小宁同学发现鼠标右键好像不管用了。 查看页面源代码方式归类 单击鼠标右键,点击查看页面源代码: …...
目前流行的9大前端框架
1. React 2. Vue 3. Angular 、 4. Svelte 官网:https://svelte.dev 中文官网:https://www.sveltejs.cn Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程…...
【mysql】explain执行计划之select_type列
目录 一、说明二、示例2.1 simple:简单表,不使用union或者子查询2.2 primary:主查询,外层的查询2.3 subquery:select、where之后包含了子查询,在select语句中出现的子查询语句,结果不依赖于外部…...
网易云音乐开发--音乐播放暂停切换上下首功能实现
音乐播放暂停功能实现 封装一个控制音乐播放/暂停的功能函数 看一下文档,我需要用的api 这个接口好像没有音频的url,查看一下,换个api 这样就能拿到id,并可以播放了 但是音乐并没有播放 我们少了这个 现在可以播放了ÿ…...
如何学习网络安全?
近半年我一直在整理网络安全相关资料,对于网络安全该怎么入门我谈谈我的看法,网络安全一直处于法律的边缘,学的不好或者剑走偏锋一下子人就进去了,所以我建议入门前先熟读《网络安全法》,除此之外还有《互联网安全产品…...
软件测试适合女生吗?
大家好,我是程序员馨馨,一个混过大厂,待过创业公司,有着 6 年工作经验的软件测试妹纸一枚。之前在也写过几篇文章,之后很多朋友过来咨询女生能不能做软件测试。 今天索性写篇文章,详细的介绍一下软件测试&a…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...
