当前位置: 首页 > 后端技术 > Java

MyBatis原生批量插入的坑及解决办法!

时间:2023-04-01 21:31:26 Java

上一篇我们讲了MyBatis批量插入的三种方式:循环单次插入、MyBatisPlus批量插入、MyBatis原生批量插入。详情请点击《MyBatis 批量插入数据的 3 种方法!》。然而,之前的文章并不完美。原因是:使用“循环单插入”性能太低,使用“MyBatisPlus批量插入”性能还不错,但需要额外引入MyBatisPlus框架,使用“MyBatisNative”批量插入"性能最好,但是在插入大量数据的时候会导致程序出错,所以今天我们提供一个更好的解决方案。原生批量插入的“坑”首先我们来看一下MyBatis原生批量插入的坑。当我们批量插入10万条数据时,实现代码如下:importcom.example.demo.model.User;importcom.example.demo.service.impl.UserServiceImpl;importorg.junit.jupiter.api。Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importjava.util.ArrayList;importjava.util.List;@SpringBootTestclassUserControllerTest{//最大数量循环privatestaticfinalintMAXCOUNT=100000;@AutowiredprivateUserServiceImpl用户服务;/***自己原生拼接SQL,批量插入*/@TestvoidsaveBatchByNative(){longstime=System.currentTimeMillis();//统计开始时间Listlist=newArrayList<>();for(inti=0;iINSERTINTO`USER`(`NAME`,`PASSWORD`)VALUES(#{item.name},#{item.password})当我们愉快的运行上面的程序时,出现了如下场景:哇,程序报错了!这是因为使用MyBatis原生的批量插入拼接插入的SQL大小为4.56M,而默认情况下MySQL最多可以执行的SQL为4M,那么程序执行的时候就会报错。拼接的SQL文件过大,MySQL执行会报错。那么我们第一时间想到的解决办法就是把大文件分成N个小文件,这样就不会因为SQL太大而报执行错误了。也就是说,我们可以将待插入的List集合划分成多个小的List进行批量插入操作,这个操作过程称为List分片。有了处理思路之后,接下来就是实践了,那么如何对集合进行分片呢?实现sharding操作的方式有很多种,后面会讲到,然后我们用最简单的方式,就是Google提供的Guava框架来实现sharding功能。分片Demo为了实现分片功能,第一步是添加对Guava框架的支持,在pom.xml中添加如下引用:com.google.guavaguava<版本>31.0.1-jre接下来我们写一个小demo,将下面7个名字分成3组(每组最多3个),实现代码如下:importcom.google.common.collect。列表;导入java。util.Arrays;importjava.util.List;/***Guavapartition*/publicclassPartitionByGuavaExample{//原始集合privatestaticfinalListOLD_LIST=Arrays.asList("唐僧、悟空、八戒、沙僧,曹操,刘备,孙权.split(","));publicstaticvoidmain(String[]args){//集合片段List>newList=Lists.partition(OLD_LIST,3);//打印切片的集合newList.forEach(i->{System.out.println("Collectionlength:"+i.size());});}}上面程序的执行结果如下:从上面的结果可以看出,我们只需要使用Guava提供的Lists.partition方法可以很容易地分割一个集合Native批量插入分区实现接下来就是改造我们的MyBatis批量插入代码,具体实现如下:@TestvoidsaveBatchByNativePartition(){longstime=System.currentTimeMillis();//统计开始时间Listlist=newArrayList<>();//构建并插入数据for(inti=0;i>listPartition=Lists.partition(list,count);//分区批量插入for(Listitem:listPartition){userService.saveBatchByNative(item);}longetime=System.currentTimeMillis();//统计结束时间System.out.println("Executiontime:"+(etime-stime));}执行上面的程序,最终的执行结果如下:从上图可以看出,前面的异常批量插入的错误没有了,而且这个实现的执行效率其实比MyBatisPlus的批量插入要高。MyBatisPlus批量插入10W条数据的执行时间如下:总结这篇文章,我们论证了MyBatis原生批量插入的问题:可能是由于插入的数据过多导致操作失败。我们可以通过分片的方式来解决这个问题。批量插入分片的实现步骤如下:计算分片数量(分为N批);使用Lists.partition方法对集合进行分片(分成N个集合);循环批量插入分片集合关注公众号「Java中文社区」查看更多MyBatis和SpringBoot的系列文章。

猜你喜欢