深入解析Mybatis-Plus框架:简化Java持久层开发(十二)

🍀 前言

博客地址:

👋 简介

本章节介绍如何通过Mybatis-Plus进行实现批量新增。

📖 正文

1 为何要批量插入?

前面章节已经介绍,Mapper接口只有一个insert单挑插入的方法,而Service接口中批量插入saveBatch的方法,也只能做到伪批量插入,实际还是利用了循环一条一条插入,这样会导致效率低,耗时长。
实际执行的SQL为

INSERT INTO tb_role ( role_name, role_code ) VALUES ( '超级管理员', 'ADMIN' )
INSERT INTO tb_role ( role_name, role_code ) VALUES ( '测试角色1号', 'TEST01' )
INSERT INTO tb_role ( role_name, role_code ) VALUES ( '测试角色2号', 'TEST02' )
INSERT INTO tb_role ( role_name, role_code ) VALUES ( '测试角色3号', 'TEST03' )

那么,我们该如何保证SQL的执行像下面这样执行呢,接下来我们开始进行操作

INSERT INTO 
	tb_role ( role_name, role_code ) 
VALUES 
	( '超级管理员', 'ADMIN' ),
	( '测试角色1号', 'TEST01' ),
	( '测试角色2号', 'TEST02' ),
	( '测试角色3号', 'TEST03' );

2 实现批量插入

这里我们将通过Mybatis-Plus框架的SQL注入器实现一个真的批量插入功能。

2.1 创建SQL注入器

在项目config目录下新增一个InsertBatchInjector类,然后继承DefaultSqlInjector类后,重新实现getMethodList方法。

package com.power.mpdemo.config;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;

import java.util.List;

/**
 * @author power
 * @time 2023/12/23 07:50:28
 * @Description
 */
public class InsertBatchInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        // super.getMethodList() 保留 Mybatis-Plus 自带的方法
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        // 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn
        methodList.add(new InsertBatchSomeColumn());
        return methodList;
    }
}

在配置类中,添加了Mybatis-Plus内部提供的默认批量插入的InsertBatchSomeColumn类,根据作者在源码中的描述,只在Mysql数据库中测试过,所以没有将该方法提供外部使用,所以当前我们这里批量插入只针对Mysql数据库。
image.png

2.2 配置SQL注入器

在前面章节,我们在config包下创建的MybatisPlusConfig类中,添加以下代码

/**
 * 自定义批量插入 SQL 注入器
 *
 * @return
 */
@Bean
public InsertBatchInjector insertBatchSqlInjector() {
    return new InsertBatchInjector();
}
2.3 配置BaseMapper

config包下,新增一个NewBaseMapper的接口,继承Mybatis-Plus的BaseMapper接口。

package com.power.mpdemo.config;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author power
 * @time 2023/12/23 08:04:55
 * @Description
 */
public interface NewBaseMapper<T> extends BaseMapper<T> {

    // 批量插入
    int insertBatchSomeColumn(@Param("list") List<T> batchList);

}

修改我们的RoleMapper继承的接口为刚才创建的新接口

package com.power.mpdemo.mapper;

import com.power.mpdemo.config.NewBaseMapper;
import com.power.mpdemo.entity.Role;

/**
 * <p>
 * 角色表 Mapper 接口
 * </p>
 *
 * @author power
 * @since 2023-12-21
 */
public interface RoleMapper extends NewBaseMapper<Role> {

}
2.4 测试执行
@Test
public void insertBatch() {
    List<Role> list = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        list.add(Role.builder()
                .roleName("批量添加" + i)
                .roleCode("batch" + i)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .isDeleted(0)
                .build()
        );
    }
    int i = roleMapper.insertBatchSomeColumn(list);
    System.out.println("添加结果:" + i);
}

// 添加结果:5

实际执行的SQL

INSERT INTO 
	tb_role (role_name,role_code,description,create_time,update_time,is_deleted) 
VALUES 
	('批量添加0','batch0',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) , 
  ('批量添加1','batch1',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) , 
  ('批量添加2','batch2',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) , 
  ('批量添加3','batch3',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0) , 
  ('批量添加4','batch4',NULL,'2023-12-23T08:14:29.860','2023-12-23T08:14:29.860',0)

3 性能对比

3.1 for循环插入
@Test
public void insertBatch() {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 10000; i++) {
        Role role = Role.builder()
        .roleName("for循环" + i)
        .roleCode("insert" + i)
        .createTime(LocalDateTime.now())
        .updateTime(LocalDateTime.now())
        .isDeleted(0)
        .build();
        roleMapper.insert(role);
    }
    System.out.printf("总耗时:%s ms%n", System.currentTimeMillis() - start);
}

// 总耗时:11460 ms
3.2 Service接口批量插入
@Test
public void insertBatch() {
    long start = System.currentTimeMillis();
    List<Role> list = new ArrayList<>();
    for (int i = 0; i < 10000; i++) {
        list.add(Role.builder()
                .roleName("Service伪批量插入" + i)
                .roleCode("saveBatch" + i)
                .build()
        );
    }
    roleService.saveBatch(list);
    System.out.printf("总耗时:%s ms%n", System.currentTimeMillis() - start);
}

// 总耗时:1743 ms
3.3 真实批量插入
@Test
public void insertBatch() {
    long start = System.currentTimeMillis();
    List<Role> list = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        list.add(Role.builder()
                .roleName("批量添加" + i)
                .roleCode("batch" + i)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .isDeleted(0)
                .build()
        );
    }
    roleMapper.insertBatchSomeColumn(list);
    System.out.printf("总耗时:%s ms%n", System.currentTimeMillis() - start);
}

// 总耗时:252 ms

Tips:
根据执行结果发现,在插入数量同为10000条数据的情况下,for循环耗时最多,我们自己实现的真实批量插入耗时最少。尽管实际应用中我们不会使用for的方式批量插入,但是同样通过Mybatis-Plus框架实现的批量插入,Service接口的saveBatch方法的批量插入的耗时是自定义实现批量插入耗时的的6-7倍,当数据量十万百万级别的,就能体现出真实批量插入的性能的重要性了

✏ 总结

💖 欢迎关注我的公众号

在这里插入图片描述

  • 34
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值