作者|王磊来源|Java中文社区(ID:javacn666)转载请联系授权(微信ID:GG_Stone)上一篇文章我们讲了MyBatis批量插入的3种方式:循环单次插入、MyBatisPlus批量插入、MyBatis原生批量插入,请戳《MyBatis 批量插入数据的 3 种方法!》了解详情。但是之前的文章并不完美,原因是:使用“循环单插入”性能太低,使用“MyBatisPlus批量插入”性能还不错,但是需要额外引入MyBatisPlus框架,使用“MyBatis原生批量插入”“插入”性能最好,但是在插入大量数据时会导致程序出错,所以今天我们提供一个更好的解决方案。原生批量插入的“坑”首先我们来看一下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;@AutowiredprivateUserServiceImpluserService;/***原生自拼接SQL,批量插入*/@TestvoidsaveBatchByNative(){longstime=System.currentTimeMillis();//统计开始时间Listlist=newArrayList<>();for(inti=0;iINSERTINTO`USER`(`NAME`,`PASSWORD`)VALUES(#{item.name},#{item.password})当我们愉快的运行上面的程序时,出现了如下场景:Wo,程序竟然报错了已经报道!这是因为使用MyBatis原生批量插入拼接的插入SQL大小为4.56M,而MySQL默认最大可执行的SQL为4M,那么程序执行时会报错。上面问题的解决方法是因为批量插入时拼接的sql文件过多,所以mysql执行报错。那么我们第一时间想到的解决办法就是把大文件分成N个小文件,这样就不会因为SQL太大而报执行错误了。也就是说,我们可以将待插入的List集合划分成多个小的List进行批量插入操作,这个操作过程称为List分片。有了加工思路之后,接下来就是实践了。如何对集合进行分片操作?有很多方法可以实现分片操作。这个我们后面会讲到,然后我们就用最简单的方法,就是Google提供的Guava框架来实现sharding的功能。ShardingDemo为了实现分片功能,首先要添加Guava框架的支持,在pom.xml中添加如下引用:com.google.guavaguava31.0.1-jre接下来我们写一个小demo,将下面7个名字分成3组(每组最多3个),实现代码如下:importcom.google.common.collect.Lists;importjava.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即可。分区方法可以很容易地对集合进行分片。原生批量插入分片实现接下来就是改造我们的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组);循环对分片集合进行批量插入操作。