一切福田,不離方寸,從心而覓,感無不通。

Mybatis/Mybatis-Plus 使用流式查询优化大量数据导出

前言

相信小伙伴们工作当中肯定会经常遇到导出数据的需求,做这个导出需求的话相信大家肯定很多人用easypoi工具包,这个工具包用起来是真的方便,爽。但是如果数据量大,产品又要你导出很多数据,这时候就不爽了,因为如果数据量大的话,服务器配置又不是很高,那么很容易就把服务器导挂了。今天就教大家一招(有能力的小伙伴也可以自行研究使用其它方式优化导出),使用mybatis/mybatis-plus中的流式查询结合阿里的easyexcel做到一边查询一边写入流的方式优化大量数据导出,这样做写入流后的数据内存就可以释放出来,从而降低jvm的内存使用率。

测试

普通导出,JVM垃圾回收图

看看代码:

导出66万多条数据,从查询到导出一共花了141.327秒
pic

在看一下jvm垃圾回收状态:
pic
可以看出,eden区垃圾回收很均匀,而且很快。old区的空间也是在均匀的增加。

直接看一下视频:

kk 2021-07-27 18-28-29

流式查询,JVM垃圾回收图

pic

先看代码:

再补充一下streamQuery方法的实现:

同样导出66万多条数据,从查询到导出一共花了55.465秒
同样看一下流式导出jvm垃圾回收状态:
pic
可以看出,eden区垃圾回收也很均匀,比普通导出更快。old区的空间也是在均匀的增加。但是流式导出eden区占用的内存并不像普通导出那样越来越大。始终稳定维持在最高280M,s0 和 s1 区则更小,都远远小于普通导出。
看一下视频:

kk 2021-07-27 18-35-13

OOM测试

接下来,把jvm最大内存固定,我就设置500M吧。看哪一种会导致OOM。

pic

普通查询导出

kk 2021-07-29 19-39-25

可以看出,普通查询导出的full gc频率很高,eden区,old区内存都用满释放不出来了。所以内存小的话普通查询导出是会导致oom的。

流式查询导出

废话不多说,相同内存分配配置,直接看视频:

kk 2021-07-29 19-51-13

从视频可以看出,流式查询导出没有oom,只是时间有点慢,导出60w数据花了182.378 秒,但是比起程序oom来说,多花点时间也不是啥大事。谁让我们配置内存太小了呢。视频中eden区和old区的内存占用都非常稳定。而且 占用的内存很小 ,流式查询导出大量数据还是很有优势的。
后来我又 测试了分配300M内存 ,普通导出一会就跪了,流式查询居然还能正常导出。只是时间要长一些,不得不说流式查询导出大数据真的很强大啊!!!

结论

通过以上实验可以得出,需要导出大量数据的情况下,使用普通查询导出是因为一次性把所有数据查询出来放在集合中,这时候gc释放不了这一部分内存,就会是堆内存用尽导致程序oom。使 用mybatis的流式查询配合alibaba的easypoi 工具, 一边查询一边导出 ,这样用过的数据写入流之后就可以gc回收掉内存空间,使内存得到合理应用, 避免了oom的发生 。

最后

我后来把导出封装了一下,配合阿里的easyexcel写了一个通用工具类,导出是真的方便!贴一下工具类代码及使用demo:

CommonResultHandler通用抽象类:

导出工具类StremExportUtil:

使用demo:

 

再看看streamQuery 方法实现:

 

好了,今天的文章就分享到这里,如果有不明白的地方欢迎留言探讨,我会第一时间回复!小伙伴们帮忙点赞哦!

 

from:https://blog.csdn.net/Dream_xun/article/details/119337583