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

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批量插入一直是开发者重点关注的问题&#xff0c;本文列举了Mybatis的五种插入方式进行对比分析&#xff0c;验证了五种批量插入的方式的优先级。 1 准备工作 1.1 新建spring项目 略。 1.2 导入pom.xml依赖 <depende…...

【系分论文】论软件开发模型及应用

目录 论题论题介绍论文要点理论素材准备范文摘要正文 论文补充知识 论题 论软件开发模型及应用 论题介绍 软件开发模型&#xff08; Software Development Model&#xff09;是指软件开发全部过程、活动和任务的结构框架。软件开发过程包括需求、设计、编码和测试等阶段&…...

渗透测试--5.3.使用john破解密码

前言 由于Linux是Internet最流行的服务器操作系统&#xff0c;因此它的安全性备受关注。这种安全主要靠口令实现。 Linux使用一个单向函数crypt&#xff08;&#xff09;来加密用户口令。单向函数crypt&#xff08;&#xff09;从数学原理上保证了从加密的密文得到加密前的明…...

Go中的变量类型

Go中的变量类型 1.为什么要使用变量 变量其实指定的是一段内存地址&#xff0c;根据这个内存地址可以找到我们需要找到的东西。 2.变量类型 变量的功能就是用来存储数据的&#xff0c;根据不同的数据类型可以存储不同的数据。常见的变量的类型 整型、浮点型、布尔型等。变…...

基于STM32的NRF24L01 2.4G通讯模块的驱动实验(HAL库)

前言&#xff1a;本文为手把手教学NRF24L01 2.4G通讯模块的驱动实验&#xff0c;本教程的 MCU 采用STM32F103ZET6与STM32F103C8T6&#xff0c;彼此进行互相通讯。通过 CubeMX 软件配置 SPI 协议驱动NRF24L01 2.4G通讯模块&#xff08;HAL库&#xff09;。NRF24L01 2.4G是嵌入式…...

DJ5-3 多路访问链路和协议

目录 一、网络链路 二、广播信道要解决问题 三、多路访问协议 1、基本介绍 2、多路访问协议的类型&#xff08;3&#xff09; 四、信道划分协议 1、时分多路访问 TDMA 2、频分多路访问 FDMA 3、码分多路访问 CDMA&#xff08;略&#xff09; 五、随机访问协议 1、纯…...

技术领导力?

作品集&#xff08;Portfolio&#xff09;会比简历&#xff08;Resume&#xff09;更有参考意义。 怎么才算有技术领导力&#xff1f; 1) 能够发现问题&#xff0c;并能够提供解决问题的思路和方案&#xff0c;并能比较方案的优缺点。 2) 能用更简洁有效的方式解决问题。 3…...

计算机的基本工作原理

参考资料&#xff1a; L-1.6: Common Bus system| How basic computer works - YouTube 准备好内存单元、不同类型的寄存器&#xff0c;内存和寄存器、寄存器和寄存器之间都是通过总线连接(假设是直接把数据总线、控制总线、地址总线变成一条总线)。 使用多路复用器实现的总线&…...

【论文简述】Cross-Attentional Flow Transformer for Robust Optical Flow(CVPR 2022)

一、论文简述 1. 第一作者&#xff1a;Xiuchao Sui、Shaohua Li 2. 发表年份&#xff1a;2021 3. 发表期刊&#xff1a;arxiv 4. 关键词&#xff1a;光流、Transformer、自注意力、交叉注意力、相关体 5. 探索动机&#xff1a;由于卷积的局部性和刚性权重&#xff0c;有限…...

【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 对等网络&#xff08;Peer-to-Peer Networks&#xff09;是分布式系统和计算机网络相结合的产物&#xff0c;在应用领域和学术界获得了广泛的重视和成功&#xff0c;被称为“改变Internet的一代网络技术”。 peer指网络结点&#xff0c;在行为上是自由的——任意加入、退…...

【笔试强训选择题】Day15.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01; 文章目录 前言 一、…...

图论专题(一)

图论专题(一) 参考文献 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

常见的网络基础介绍 前言 我们学习了一些基础的网络协议&#xff0c;以及子网掩码和vlan&#xff0c;同时也做了个简单的单臂路由实验 这篇文章我将仔细的讲解单臂路由的应用和交换机二层接口类型&#xff0c;以及wireshark的教程。 一&#xff0c;交换机二层接口 交换机的二…...

[CTF/网络安全] 攻防世界 view_source 解题详析

[CTF/网络安全] 攻防世界 view_source 解题详析 查看页面源代码方式归类总结 题目描述&#xff1a;X老师让小宁同学查看一个网页的源代码&#xff0c;但小宁同学发现鼠标右键好像不管用了。 查看页面源代码方式归类 单击鼠标右键&#xff0c;点击查看页面源代码&#xff1a; …...

目前流行的9大前端框架

1. React 2. Vue 3. Angular 、 4. Svelte 官网&#xff1a;https://svelte.dev 中文官网&#xff1a;https://www.sveltejs.cn Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作&#xff0c;而 Svelte 将这些工作放到构建应用程…...

【mysql】explain执行计划之select_type列

目录 一、说明二、示例2.1 simple&#xff1a;简单表&#xff0c;不使用union或者子查询2.2 primary&#xff1a;主查询&#xff0c;外层的查询2.3 subquery&#xff1a;select、where之后包含了子查询&#xff0c;在select语句中出现的子查询语句&#xff0c;结果不依赖于外部…...

网易云音乐开发--音乐播放暂停切换上下首功能实现

音乐播放暂停功能实现 封装一个控制音乐播放/暂停的功能函数 看一下文档&#xff0c;我需要用的api 这个接口好像没有音频的url&#xff0c;查看一下&#xff0c;换个api 这样就能拿到id&#xff0c;并可以播放了 但是音乐并没有播放 我们少了这个 现在可以播放了&#xff…...

如何学习网络安全?

近半年我一直在整理网络安全相关资料&#xff0c;对于网络安全该怎么入门我谈谈我的看法&#xff0c;网络安全一直处于法律的边缘&#xff0c;学的不好或者剑走偏锋一下子人就进去了&#xff0c;所以我建议入门前先熟读《网络安全法》&#xff0c;除此之外还有《互联网安全产品…...

软件测试适合女生吗?

大家好&#xff0c;我是程序员馨馨&#xff0c;一个混过大厂&#xff0c;待过创业公司&#xff0c;有着 6 年工作经验的软件测试妹纸一枚。之前在也写过几篇文章&#xff0c;之后很多朋友过来咨询女生能不能做软件测试。 今天索性写篇文章&#xff0c;详细的介绍一下软件测试&a…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...