Mybatis-Plus 的 IService 接口在处理大量数据插入时,逐条插入与一次性批量插入的效率对比

1. Mybatis-Plus 的 IService 接口在处理大量数据插入时,逐条插入与一次性批量插入的效率对比

准备工作:

我们先准备一张user表,现在这张表为空表,接下来我会用逐条插入与一次性批量插入两种方式去往这张表中添加10w条数据。
在这里插入图片描述

接下来搭建SpirngBoot工程,配和Mybatis-Plus实现了对user表的后端工程结构的搭建

在这里插入图片描述


1.1 使用循环逐条加入10w条数据

代码如下:

package com.mp.service;

import com.mp.domain.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class IUserServiceTest {
    @Autowired
    private IUserService userService;

    @Test
    public void testInsert() {
        long begin = System.currentTimeMillis();
        int total = 10_0000;
        for (int i = 0; i < total; i++) {
            userService.save(buildUser(i));
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - begin) + "毫秒");
    }

    private User buildUser(int i) {
        User user = new User();
        user.setUsername("user_" + i);
        user.setPassword("password_" + i);
        return user;
    }
}

运行结果:
在这里插入图片描述

在这里插入图片描述

耗时197秒,可以看到速度非常慢。使用循环插入10w数据,相当于进行了10w次网络请求,所以非常耗费时间和资源。


1.2 使用批量插入10w条数据

首先我们先清空user表的数据

truncate table user

在这里插入图片描述

代码如下:

package com.mp.service;

import com.mp.domain.po.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest
class IUserServiceTest {
    @Autowired
    private IUserService userService;

    @Test
    void testSaveBatch() {
        // 准备10万条数据
        List<User> list = new ArrayList<>(1000);
        long begin = System.currentTimeMillis();
        for (int i = 1; i <= 100000; i++) {
            list.add(buildUser(i));
            // 每1000条批量插入一次
            if (i % 1000 == 0) {
                userService.saveBatch(list);
                list.clear();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:" + (end - begin) + "毫秒");
    }

    private User buildUser(int i) {
        User user = new User();
        user.setUsername("user_" + i);
        user.setPassword("password_" + i);
        return user;
    }
}

在这里插入图片描述
在这里插入图片描述

耗时15秒,执行时间快了很多。这样做了以后虽然网络请求的次数下降为100次,但是最终在数据库执行时还是会有多条insert语句,逐条插入数据。SQL类似这样:

INSERT INTO `mp`.`user` (`id`, `username`, `password`)
 VALUES (1815321338194673665, 'user_1', 'password_1');
 
INSERT INTO `mp`.`user` (`id`, `username`, `password`)
 VALUES (1815321338224033794, 'user_2', 'password_2');
 
INSERT INTO `mp`.`user` (`id`, `username`, `password`) 
VALUES (1815321338224033795, 'user_3', 'password_3');

而如果想要得到最佳性能,最好是将多条SQL合并为一条,像这样:

INSERT INTO `mp`.`user` (`id`, `username`, `password`)
VALUES (1815321338194673665, 'user_1', 'password_1')
     , (1815321338224033794, 'user_2', 'password_2')
     , (1815321338224033795, 'user_3', 'password_3')

该怎么做呢?可以利用MySQL的rewriteBatchedStatements参数实现这种效果


1.3 开启rewriteBatchedStatements配置重试批量插入

MySQL的客户端连接参数中有这样的一个参数:rewriteBatchedStatements。顾名思义,就是重写批处理的statement语句。参考文档:

Performance Extensions

在这里插入图片描述

这个参数的默认值是false,我们需要修改连接参数,将其配置为true

修改项目中的application.yml文件,在jdbc的url后面添加参数&rewriteBatchedStatements=true:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

接下来我们再次清空user表的数据

truncate table user

然后再次执行批量插入的测试代码,发现这次插入10w条数据只耗时3s
在这里插入图片描述

在这里插入图片描述


1.4 总结

关于Mybatis-Plus的IService接口在处理大量数据插入时,逐条插入与批量插入的效率对比。文章通过实验比较了两种插入方式的性能差异。

  1. 实验准备:准备了一张空的user表,并使用SpringBoot结合Mybatis-Plus搭建了后端工程。

  2. 逐条插入:编写了一个循环,逐条插入10万条数据,并记录了操作的耗时。结果显示,逐条插入耗时197秒,效率较低。

  3. 批量插入:清空了user表,然后使用批量插入的方式插入数据,每1000条数据执行一次插入操作。结果显示,批量插入耗时15秒,效率明显提高。

  4. 最佳性能:尽管批量插入提高了效率,但在数据库执行时仍然是多条INSERT语句。为了获得最佳性能,应将多条SQL合并为一条,这可以通过设置MySQL的rewriteBatchedStatements参数为true来实现。

  5. 开启rewriteBatchedStatements配置:修改了项目的配置文件,添加了rewriteBatchedStatements=true参数,并再次执行了批量插入测试。这次插入10万条数据仅耗时3秒,显示出显著的性能提升。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeJiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值