MyBatis原生批量插入的坑与解决方案!

发布时间:2025-05-16 13:04:31 作者:益华网络 来源:undefined 浏览量(1) 点赞(2)
摘要:作者 | 王磊 来源 | Java中文社群(ID:javacn666) 转载请联系授权(微信ID:GG_Stone) 前面的文章咱们讲了 MyBatis 批量插入的 3 种方法:循环单次插入、MyBatis Plus 批量插入、MyBatis 原生批量插入,详情请点击《MyBatis 批量插入数据的 3 种方法!》。 但之前的文

作者 | 王磊

来源 | Java中文社群(ID:javacn666)

转载请联系授权(微信ID:GG_Stone)

前面的文章咱们讲了 MyBatis 批量插入的 3 种方法:循环单次插入、MyBatis Plus 批量插入、MyBatis 原生批量插入,详情请点击《MyBatis 批量插入数据的 3 种方法!》。

但之前的文章也有不完美之处,原因在于:使用 「循环单次插入」的性能太低,使用「MyBatis Plus 批量插入」性能还行,但要额外的引入 MyBatis Plus 框架,使用「MyBatis 原生批量插入」性能最好,但在插入大量数据时会导致程序报错,那么,今天咱们就会提供一个更优的解决方案。

原生批量插入的“坑”

首先,我们来看一下 MyBatis 原生批量插入中的坑,当我们批量插入 10 万条数据时,实现代码如下:

import com.example.demo.model.User; import com.example.demo.service.impl.UserServiceImpl; 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 UserControllerTest {     // 最大循环次数     private static final int MAXCOUNT = 100000;     @Autowired     private UserServiceImpl userService;     /**      * 原生自己拼接 SQL,批量插入      */     @Test     void saveBatchByNative() {         long stime = System.currentTimeMillis(); // 统计开始时间         List<User> list = new ArrayList<>();         for (int i = 0; i < MAXCOUNT; i++) {             User user = new User();             user.setName("test:" + i);             user.setPassword("123456");             list.add(user);         }         // 批量插入         userService.saveBatchByNative(list);         long etime = System.currentTimeMillis(); // 统计结束时间         System.out.println("执行时间:" + (etime - stime));     } }

核心文件 UserMapper.xml 中的实现代码如下:

<!-- google guava 工具类 --> <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency>   <groupId>com.google.guava</groupId>   <artifactId>guava</artifactId>   <version>31.0.1-jre</version> </dependency>

接下来我们写一个小小的 demo,将以下 7 个人名分为 3 组(每组最多 3 个),实现代码如下:

import com.google.common.collect.Lists; import java.util.Arrays; import java.util.List; /**  * Guava 分片  */ public class PartitionByGuavaExample {     // 原集合     private static final List<String> OLD_LIST = Arrays.asList(             "唐僧,悟空,八戒,沙僧,曹操,刘备,孙权".split(","));     public static void main(String[] args) {         // 集合分片         List<List<String>> newList = Lists.partition(OLD_LIST, 3);         // 打印分片集合         newList.forEach(i -> {             System.out.println("集合长度:" + i.size());         });     } }

以上程序的执行结果如下:

从上述结果可以看出,我们只需要使用 Guava 提供的 Lists.partition 方法就可以很轻松的将一个集合进行分片了。

原生批量插入分片实现

那接下来,就是改造我们的 MyBatis 批量插入代码了,具体实现如下:

@Test void saveBatchByNativePartition() {     long stime = System.currentTimeMillis(); // 统计开始时间     List<User> list = new ArrayList<>();     // 构建插入数据     for (int i = 0; i < MAXCOUNT; i++) {         User user = new User();         user.setName("test:" + i);         user.setPassword("123456");         list.add(user);     }     // 分片批量插入     int count = (int) Math.ceil(MAXCOUNT / 1000.0); // 分为 n 份,每份 1000 条     List<List<User>> listPartition = Lists.partition(list, count);     // 分片批量插入     for (List<User> item : listPartition) {         userService.saveBatchByNative(item);     }     long etime = System.currentTimeMillis(); // 统计结束时间     System.out.println("执行时间:" + (etime - stime)); }

执行以上程序,最终的执行结果如下:

从上图可以看出,之前批量插入时的异常报错不见了,并且此实现方式的执行效率竟比 MyBatis Plus 的批量插入的执行效率要高,MyBatis Plus 批量插入 10W 条数据的执行时间如下:

总结本文我们演示了 MyBatis 原生批量插入时的问题:可能会因为插入的数据太多从而导致运行失败,我们可以通过分片的方式来解决此问题,分片批量插入的实现步骤如下:

计算出分片的数量(分为 N 批); 使用 Lists.partition 方法将集合进行分片(分为 N 个集合); 循环将分片的集合进行批量插入的操作。

二维码

扫一扫,关注我们

声明:本文由【益华网络】编辑上传发布,转载此文章须经作者同意,并请附上出处【益华网络】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15368564009
在线客服
嘿,我来帮您!