最近 Review 小伙伴代码的时候,发现了一个小小的问题,小伙伴竟然在 for 循环中进行了 insert (插入)数据库的操作,这就会导致每次循环时都会进行连接、插入、断开连接的操作,从而导致一定的性能问题,简化后代码如下:

/**
* 插入操作
*/
@RequestMapping("/save")
public Object save() {
boolean flag = false; // 返回结果
// 待添加(用户)数据
for (int i = 0; i < 1000; i++) {
User user = new User();
user.setName("test:"+i);
user.setPassword("123456");
// 插入数据
flag = userService.save(user);
if(!flag) break;
}
return flag;
}

这样做并不会改变程序最终的执行结果,但会对程序的执行效率带来很大的影响,就好比你现在要从 A 地点送 10 件货到 B 地点,你可以选择 1 次送 1 件,送 10 次的方案;也可以选择 1 次送 10 件,送 1 次的方案,请问你会选择哪种?这就是多次循环插入和批量一次插入的问题。

PS:要插入的数据量越大,批量插入的时间(相比于循环多次插入来说)也越短、其优势也越大。

批量插入实现方案

本文我们使用 MyBatis-Plus(下文简称 MP)自带的 saveBatch 方法,来实现数据的批量插入功能,因为 MP 不是本文讨论的重点,所以这里咱们就不介绍了,如果有不熟悉的朋友可以去他的官方自行恶补:https://baomidou.com/guide/,咱们本文重点介绍一下 MP 实现批量插入的具体步骤。

1.引入 MP 框架

首先,打开您的 pom.xml 文件,在文件中添加以下内容:

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>mybatis-plus-latest-version</version>
</dependency>

注意:mybatis-plus-latest-version 表示 MP 框架的最新版本号,可访问 https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter 查询最新版本号,但在使用的时候记得一定要将上面的 “mybatis-plus-latest-version”替换成换成具体的版本号,如 3.4.3 才能正常的引入框架。

2.创建数据库和表

此步骤可省略,主要用于本文功能的实现,创建数据库和数据表的脚本如下:

-- ----------------------------
-- 创建数据库
-- ----------------------------
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP DATABASE IF EXISTS `testdb`;
CREATE DATABASE `testdb`;
USE `testdb`; -- ----------------------------
-- 创建 user 表
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`createtime` datetime NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic; -- ----------------------------
-- 添加测试数据
-- ----------------------------
INSERT INTO `user` VALUES (1, '赵云', '123456', '2021-09-10 18:11:16');
INSERT INTO `user` VALUES (2, '张飞', '123456', '2021-09-10 18:11:28');
INSERT INTO `user` VALUES (3, '关羽', '123456', '2021-09-10 18:11:34');
INSERT INTO `user` VALUES (4, '刘备', '123456', '2021-09-10 18:11:41');
INSERT INTO `user` VALUES (5, '曹操', '123456', '2021-09-10 18:12:02'); SET FOREIGN_KEY_CHECKS = 1;

3.具体代码实现(重点)

① 实体类

先来创建数据库所对应的 User 实体类:

import lombok.Getter;
import lombok.Setter; import java.util.Date; @Getter
@Setter
public class User {
private int id;
private String name;
private String password;
private Date createtime;
}

② Controller 层代码

本文的核心是使用 MP 框架中,IService 类提供的 saveBatch 方法,来实现批量数据的插入功能,对应在 Controller 中的实现代码如下:

import com.example.demo.model.User;
import com.example.demo.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList;
import java.util.List; @RestController
@RequestMapping("/u")
public class UserController { @Autowired
private UserServiceImpl userService; /**
* MP 批量插入
*/
@RequestMapping("/savebatch")
public boolean saveBatch() {
List<User> list = new ArrayList<>();
// 待添加(用户)数据
for (int i = 0; i < 1000; i++) {
User user = new User();
user.setName("test:"+i);
user.setPassword("123456");
list.add(user);
}
// 批量插入
return userService.saveBatch(list);
}
}

③ Service 层代码(重点)

接下来,我们要创建一个 UserService 接口,继承 MP 框架中的 IService 接口,实现代码如下:

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.demo.model.User; public interface UserService extends IService<User> { }

然后再创建一个 UserService 的实现类:

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.stereotype.Service; @Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User>
implements UserService { }

PS:注意 UserServiceImpl 必须要继承 MP 框架中的 ServiceImpl,不然要重写很多方法。

④ Mapper 层代码

Mapper 层的实现相对来说就比较简单了,只需要创建一个 Mapper 类继承 MP 框架中的 BaseMapper 类即可,实现代码如下:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.model.User;
import org.apache.ibatis.annotations.Mapper; @Mapper
public interface UserMapper extends BaseMapper<User>{ }

PS:BaseMapper 提供了对某个对象(类)最基础的 CRUD 操作。

总结

本文我们介绍了 MP(MyBatis Plus)中实现批量插入的具体实现步骤,它的核心是通过调用 MP 中 IService 提供的 saveBatch 方法来完成的,但如果项目中没有引入 MP 框架该如何处理?是不是使用了 MP 就可以躺平了呢?不着急,下篇我们再聊批量插入的另一种方式(原生批量插入的实现方式),以及二者之间的优缺点分析。

关注公号「Java中文社群」查看更多 MyBatis 和 Spring Boot 的系列文章。

MyBatis Plus 批量数据插入功能,yyds!的更多相关文章

  1. yii批量数据插入

    yii框架批量插入数据有两种方法,第一种是循环多次插入和一次批量插入,第一种方法要注意插入数据中间有一次数据插入失败要注意回滚事务 循环插入数据 第一种方法 $model = new User(); ...

  2. EF结合SqlBulkCopy实现高效的批量数据插入 |EF插件EntityFramework.Extended实现批量更新和删除

    原文链接:http://blog.csdn.net/fanbin168/article/details/51485969   批量插入 (17597条数据批量插入耗时1.7秒)   using Sys ...

  3. [oracle/java/sql]用于上十万批量数据插入Oracle表的Java程序

    程序下载:https://files.cnblogs.com/files/xiandedanteng/LeftInnerNotExist20191222.rar 原理:Oracle的Insert al ...

  4. 原创 SqlParameter 事务 批量数据插入

    不错,很好,以后防注入批量事务提交虽然麻烦点研究了几个小时,但不会是问题了 SqlCommand cmd; HelpSqlServer helps = new HelpSqlServer(); //定 ...

  5. 使用SqlBulkCopy进行批量数据插入

    Dim dt As DataTable = New DataTable() dt.Columns.Add("DtCostProductRuleGUID", GetType(Guid ...

  6. MyBatis中批量插入数据对插入记录数的限制

    <基于Mybatis框架的批量数据插入的性能问题的探讨>(作者:魏静敏 刘欢杰 来源:<计算机光盘软件与应用> 2013 年第 19 期)中提到批量插入的记录数不能超过1000 ...

  7. KingbaseES批量数据加载的实践技巧

    有时,KingbaseES数据库需要在单个或最少的步骤中导入大量数据,这通常称为批量数据导入.其中数据源通常是一个或多个大文件,这个过程有时可能非常慢. 造成性能不佳的原因有很多:索引.触发器.外键. ...

  8. myBatis获取批量插入数据的主键id

    在myBatis中获取刚刚插入的数据的主键id是比较容易的 , 一般来说下面的一句话就可以搞定了 , 网上也有很多相关资料去查. @Options(useGeneratedKeys = true, k ...

  9. mybatis foreach批量插入数据:Oracle与MySQL区别

    mybatis foreach批量插入数据:Oracle与MySQL不同点: 主要不同点在于foreach标签内separator属性的设置问题: separator设置为","分 ...

随机推荐

  1. Docker小白到实战之容器数据卷,整理的明明白白

    前言 上一篇把常用命令演示了一遍,其中也提到容器的隔离性,默认情况下,容器内应用产生的数据都是由容器本身独有,如果容器被删除,对应的数据文件就会跟着消失.从隔离性的角度来看,数据就应该和容器共存亡:但 ...

  2. COM笔记-COM库函数

    COM在OLE32.DLL和 OLE32.LIB定义了一些常用的函数.在使用这些函数前要先调用CoInitialize来初始化COM库.当进程不再需要使用COM库函数时要调用CoUninitializ ...

  3. vs2019 快捷键汇总

    https://docs.microsoft.com/zh-cn/visualstudio/ide/default-keyboard-shortcuts-for-frequently-used-com ...

  4. Semaphore 类 的使用理解C#

    示例 下面的代码示例创建一个信号量,其最大计数为3,初始计数为零. 该示例启动五个线程,这会阻止等待信号量. 主线程使用 Release(Int32) 方法重载将信号量计数增加到其最大值,从而允许三个 ...

  5. Javascript - Vue - 在vscode里使用webpack

    cnpm(node package manager)和webpack模块 npm是运行在node.js环境下的包管理工具,使用npm可以很快速的安装前端文件里需要依赖的那些项目文件,比如js.css文 ...

  6. 基于mysql和Java Swing的简单课程设计

    摘要 现代化的酒店组织庞大.服务项目多.信息量大.要想提高效率.降低成本.提高服务质量和管理水平,进而促进经济效益,必须利用电脑网络技术处理宾馆酒店经营数据,实现酒店现代化的信息管理.本次课程设计运用 ...

  7. 进程CPU、内存过高问题查找

    1.定位进程 找出占用CPU最高的10个进程 ps aux | sort -k3nr | head -n 10 查看占用内存最高的10个进程 ps aux | sort -k4nr | head -n ...

  8. ES6扩展——数组扩展

    1.结合扩展运算符使用.通过扩展运算符,在调用函数的时候,把一个数组展开,然后作为这个函数的参数 //结合扩展运算符使用 function foo(a,b,c){ console.log(a); // ...

  9. 那些优秀的python代码

    时间:2019-04-18 收藏:PangYuaner 标题:Python如何生成树形图案 地址:https://www.jb51.net/article/132049.htm 标题:用python- ...

  10. 板子题 Sol

    RT Cyber_Tree 出了一道板子题... 这题乍看之下貌似还不戳,但如果您做过类似的题,那么这就是一道板子题.... 首先明确要求的是什么,如果我们只考虑权值最大而不考虑最小距离,那么要求的显 ...