Jdbc批处理功能和MybatisPlus

news/2025/1/16 1:08:55/

文章目录

  • 1. 序言
  • 2. JDBC批处理功能和rewriteBatchedStatements
  • 3. JDBC批量插入的测试
  • 4. MybatisPlus#ServiceImpl.saveBatch()
  • 5. 结语:如果对大家有帮助,请点赞支持。如果有问题随时在评论中指出,感谢。

1. 序言

MybatisPlus的ServiceImpl类中提供了批处理方法saveBatch,用来批量插入数据,速度要比”一个一个”插入更快。而这个方法的底层依赖了JDBC数据库驱动的批处理功能。
本文先介绍JDBC数据库驱动的批处理功能,然后对"JDBC批量插入"进行性能测试,从而说明saveBatch快的原因,最后说明MybatisPlus ServiceImpl.saveBatch的最佳使用方式(其实就一句话)。

2. JDBC批处理功能和rewriteBatchedStatements

  • JDBC批处理功能是指:将多条SQL语句打包起来,一次性发给数据库服务器,服务器执行后将结果返回给客户端。相对于单条SQL逐条发送,批处理功能可以减少网络传输开销。JDBC的Statement和PreparedStatement都支持批处理,下面测试基于PreparedStatement。
    • PreparedStatement.addBatch()用来添加一条SQL到列表中,但是不会提交给服务器。
    • PreparedStatement.executeBatch()将列表中的所有SQL提交给服务器,并获得执行结果。
  • rewriteBatchedStatements:假如数据库URL连接设置了参数rewriteBatchedStatements=true,那么执行executeBatch()时,多条INSERT语句就会被重写为一条INSERT语句,再发送给服务器,使得插入速度更快。默认值为false。

3. JDBC批量插入的测试

  1. 配置:MySQL驱动 8.3.0,两台电脑:PC1运行MySQL服务器,PC2作为客户端运行以下测试程序,PC1和PC2在同一局域网。
  2. 表结构:
	CREATE TABLE `user` (`id` bigint NOT NULL,`username` varchar(255) NOT NULL,`age` int NOT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
  1. 获取数据库连接代码
java">	private Connection getConnection() throws Exception {String url = "jdbc:mysql://192.168.1.9:3306/jdbc";String username = "root";String password = "root";return DriverManager.getConnection(url, username, password);}
  1. 逐条插入:耗时171172 ms
java">    @Testpublic void testSingleInsert() throws Exception {long start = System.currentTimeMillis();// 逐条SQL语句发送Connection conn = getConnection();PreparedStatement psmt = conn.prepareStatement("INSERT INTO user VALUES (?, ?, ?)");for (int i=1; i<=10000; i++) {psmt.setLong(1, i);psmt.setString(2, "user_" + i);psmt.setInt(3, 17);psmt.execute();}long end = System.currentTimeMillis();
//       171172 msSystem.out.println("cost = " + (end-start) + " ms");}
  1. 批量插入:耗时116244 ms,使用批处理减少了网络开销,变快了。
java">    @Testpublic void testBatchInsert() throws Exception {long start = System.currentTimeMillis();// 批量SQL发送Connection conn = getConnection();PreparedStatement psmt = conn.prepareStatement("INSERT INTO user VALUES (?, ?, ?)");for (int i=1; i<=10000; i++) {psmt.setLong(1, i);psmt.setString(2, "user_" + i);psmt.setInt(3, 17);psmt.addBatch();if (i % 1000 == 0) {psmt.executeBatch();}}long end = System.currentTimeMillis();
//        116244 msSystem.out.println("cost = " + (end-start) + " ms");}

注意:经过测试,如果MySQL服务器和客户端运行在同一台PC,"批量插入"和上一个"逐条插入"花费时间差不多,因为网络传输消耗的时间太小。

  1. 批量插入 + 手动开启事务:耗时68922 ms
    上一个"批量插入"的例子,服务器执行每一条INSERT SQL都会自动开启和提交事务。而"批量插入 + 手动开启事务"只开启和提交了一次事务,所以速度会更快。
java">    @Testpublic void testBatchInsertWithTransaction() throws Exception {long start = System.currentTimeMillis();// 批量SQL发送Connection conn = getConnection();conn.setAutoCommit(false);PreparedStatement psmt = conn.prepareStatement("INSERT INTO user VALUES (?, ?, ?)");for (int i=1; i<=10000; i++) {psmt.setLong(1, i);psmt.setString(2, "user_" + i);psmt.setInt(3, 17);psmt.addBatch();if (i % 1000 == 0) {psmt.executeBatch();}}conn.commit();long end = System.currentTimeMillis();//cost = 68922 msSystem.out.println("cost = " + (end-start) + " ms");}
  1. 批量插入 + 手动开启事务 + rewriteBatchedStatements:耗时1532 ms
java">    private Connection getConnection() throws Exception {// 添加参数rewriteBatchedStatements=trueString url = "jdbc:mysql://192.168.1.9:3306/jdbc?rewriteBatchedStatements=true";String username = "root";String password = "root";return DriverManager.getConnection(url, username, password);}@Testpublic void testBatchInsertWithTransactionAndRewrite() throws Exception {long start = System.currentTimeMillis();// 批量SQL发送,Connection conn = getConnection();conn.setAutoCommit(false);PreparedStatement psmt = conn.prepareStatement("INSERT INTO user VALUES (?, ?, ?)");for (int i=1; i<=10000; i++) {psmt.setLong(1, i);psmt.setString(2, "user_" + i);psmt.setInt(3, 17);psmt.addBatch();if (i % 1000 == 0) {psmt.executeBatch();}}conn.commit();long end = System.currentTimeMillis();//cost = 1532 msSystem.out.println("cost = " + (end-start) + " ms");}

可见"批量插入 + 手动开启事务 + rewriteBatchedStatements"速度最快。

4. MybatisPlus#ServiceImpl.saveBatch()

MybatisPlus 3.5.8
ServiceImpl.saveBatch()
可以看到ServiceImpl.saveBatch是开启了事务的,因此性能 = “批量插入 + 手动开启事务”。
所以通常我们会在JDBC数据库连接的后面加上rewriteBatchedStatements=true,变成"批量插入 + 手动开启事务 + rewriteBatchedStatements",达到最佳性能。
因此MybatisPlus批量插入的最佳方式是:saveBatch + rewriteBatchedStatements。

5. 结语:如果对大家有帮助,请点赞支持。如果有问题随时在评论中指出,感谢。


http://www.ppmy.cn/news/1545078.html

相关文章

大模型微调:Adapter;在大模型基础上增加低秩矩阵或者adapter有什么用,这样还增加运算

目录 大模型微调:Adapter 一、Adapter的具体实现方式 二、为何能在大模型基础上实现特定功能 三、举例说明 在大模型基础上增加低秩矩阵或者adapter有什么用,这样还增加运算 增加低秩矩阵的用途和优势 增加Adapter的用途和优势 关于运算复杂性的考虑 大模型微调:Ada…

软件对象粒度控制与设计模式在其中作用的例子

在软件设计中&#xff0c;确定对象的粒度&#xff08;Granularity&#xff09;是一个重要的考量因素&#xff0c;它决定了对象的职责范围和复杂程度。粒度过细或过粗都可能影响系统的可维护性和性能。设计模式可以帮助我们在不同层面控制粒度和管理对象之间的交互。以下是对每种…

Chrome和夸克谁更护眼

在当今数字化时代&#xff0c;我们每天长时间面对电脑和手机屏幕&#xff0c;眼睛的健康问题变得越来越重要。浏览器作为我们日常使用频率极高的工具&#xff0c;其护眼功能的优劣直接影响到我们的视觉舒适度。本文将对Chrome和夸克两款主流浏览器进行对比&#xff0c;探讨它们…

构建多维分类知识库:Spring Boot实战

1 绪论 1.1 研究背景 在这个推荐个性化的时代&#xff0c;采用新技术开发一个多维分类的知识管理系统来分享和展示内容是一个永恒不变的需求。本次设计的多维分类的知识管理系统有管理员和用户两个角色。 管理员可以管理用户信息&#xff0c;知识分类&#xff0c;知识信息等&am…

制造业仓储信息化总体规划方案

文件是一份关于制造业仓储信息化的总体规划方案&#xff0c;主要内容包括项目背景、现状调研、项目目标、建设思路、业务蓝图设计方案、系统设计方案以及场景展示等。以下是对PPT内容的分析和总结&#xff1a; 1. 项目背景 目标&#xff1a;通过物流执行系统&#xff08;LES&a…

3^100的位数判断

3^100的位数判断 问题来源 字节面试&#xff0c;面试官提问&#xff1a;口算估计3^100的位数&#xff0c;或是给出位数估计范围。 解决方案 方法一&#xff1a; 该方法纯口算&#xff0c;可得一个较为准确的一个范围 2 100 < 3 100 < 4 100 2^{100}<3^{100}<…

excel文档加密如何设置?电脑小白也会用的4种加密方法,30s轻松学!

excel文档加密如何设置&#xff1f;Excel文档承载着大量的敏感信息&#xff0c;如财务数据、客户信息、业务报告等。 一旦这些信息被泄露&#xff0c;可能会给企业或个人带来严重的损失。 因此&#xff0c;对Excel文档进行加密&#xff0c;确保其安全性&#xff0c;显得尤为重…

实用篇:postman汉化教程

下载postman对应版本的汉化包 在postman安装目录下默认在C:\Users\用户名\AppData\Local\Postman\app-9.12.2\resources,放入解压后的汉化包 重启就可以了