100万数据导出,居然爆炸了OutOfMemoryError?【EasyPoi实战系列】- 第472篇

news/2024/11/25 9:31:17/

历史文章(文章累计460+)

《国内最全的Spring Boot系列之一》

《国内最全的Spring Boot系列之二》

《国内最全的Spring Boot系列之三》

《国内最全的Spring Boot系列之四》

《国内最全的Spring Boot系列之五》

《国内最全的Spring Boot系列之六》

用Midjourney画个美女,AI绘画也太强大了!!! - 第8篇

【EasyPoi实战系列】Spring Boot使用EasyPoi的注解让表格更漂亮以及图片的导出 - 第468篇

推荐一款idea神级代码插件【Bito-ChatGPT】而且免费!- 第9篇

【EasyPoi实战系列】Spring Boot使用EasyPoi实现一对多的导出 - 第469篇

【EasyPoi实战系列】Spring Boot使用EasyPoi实现多Sheet导出 - 第470篇

【EasyPoi实战系列】Spring Boot使用EasyPoi动态控制导出的列 - 第471篇

悟纤:师傅,这回真的玩脱了。

师傅:怎么说,你又搞啥了见不得人的的事情。

悟纤:你这脑洞现在可以了,什么叫见不得人的事情。

师傅:那现在还有事情可以难得住你呐。

悟纤:这一次夸大了,产品让我把数据库100万的用户数据导出,我以为会很顺呢,结果导出半天,数据没导出,程序直接就炸了GC overhead limit exceeded。

师傅:这个大数据的导出,是不能用普通的导出数据的方式的,今天师傅就给你放个大招。

悟纤:师傅,你真是我的救世主,在我最困难的时候,总能来救助我。

师傅:好话就不用说了,解决问题之后,请我去吃一顿好的。

悟纤:师傅,你说这个是事情吗,别说是一顿,十顿饭都不成问题。

悟纤:问题搞起,饭饭搞起~

导读

Hi,大家好,我是悟纤

我就是我,不一样的烟火。我就是我,与众不同的小苹果。

大数据导出是当我们的导出数量在几万,到上百万的数据时,一次从数据库查询这么多数据加载到内存然后写入会对我们的内存和CPU都产生压力,这个时候需要我们像分页一样处理导出分段写入Excel缓解Excel的压力。

说明:本节的例子的导出实体类是基于前面的章节的实体类进行使用的,所以看的有点蒙圈的小伙伴可以查看前面的文章:

👇🏻👇🏻👇🏻EasyPoi实战系列

01.《【EasyPoi实战系列】Spring Boot集成EasyPoi - 第467篇》

02.《【EasyPoi实战系列】Spring Boot使用EasyPoi的注解让表格更漂亮以及图片的导出 - 第468篇》

03.《【EasyPoi实战系列】Spring Boot使用EasyPoi实现一对多的导出 - 第469篇》

04.《【EasyPoi实战系列】Spring Boot使用EasyPoi实现多Sheet导出 - 第470篇》

05.《【EasyPoi实战系列】Spring Boot使用EasyPoi动态控制导出的列 - 第471篇》

一、问题的提出

产品:悟纤,将数据库100万的用户信息导出一下~

悟纤:好的,马上。

这不开发好的导出功能吗,这个还不简单么,今天绝对不能加班了。

于是,我写了这么一段代码:

/** * 大数据导出1.0 * /demo/exportExcel4 * @param response */@GetMapping("/exportExcel4")public void exportExcel4(HttpServletResponse response) throws IOException {    Date start = new Date();    // 模拟数据    List<UserExportVO> users = new ArrayList<>();    for (int i = 0; i < 1000000; i++) {  //一百万数据量        users.add(new UserExportVO("悟纤-"+i,1,new Date(),"18688888888","abc"+i+"@qq.com",null,"公众号SpringBoot"));    }    ExcelUtil.exportExcelX(users, "测试导出表", "sheet1", UserExportVO.class, "测试导出表.xlsx", response);    System.out.println("耗时:"+(new Date().getTime() - start.getTime())/1000+"秒");}

能否导出?能,导出耗时:115秒,导出文件大小:157M。

二、大数据导出

导出是能够与导出了,但是耗时太长了,有办法减半吗?导出文件大小太大了,能办法减半吗?

必须的,这就是这节要介绍的,大数据导出。

大数据导出是当我们的导出数量在几万,到上百万的数据时,一次从数据库查询这么多数据加载到内存然后写入会对我们的内存CPU都产生压力,这个时候需要我们像分页一样处理导出分段写入Excel缓解Excel的压力。

大数据导出主要是使用到了ExcelExportUtil.exportBigExcel的方法:

欧了,那就来写个小栗子,看看效果如何:

/** * 大数据导出2.0 * /demo/exportExcel5 * @param response */@GetMapping("/exportExcel5")public void exportExcel5(HttpServletResponse response) throws IOException {    Date start = new Date();    Workbook workbook = null;    ExportParams params = new ExportParams("大数据测试", "测试");    workbook = ExcelExportUtil.exportBigExcel(params, UserExportVO.class, new IExcelExportServer() {        @Override        public List<Object> selectListForExcelExport(Object obj, int page) {            if (((int) obj) == page) {                return null;            }            List<Object> list = new ArrayList<Object>();            for (int i = 0; i < 10000; i++) {//1页查询1万,总共100页,100万数据.                list.add(new UserExportVO("悟纤-"+i,1,new Date(),"18688888888","abc"+i+"@qq.com",null,"公众号SpringBoot"));            }            return list;        }    }, 100);    ExcelUtil.downLoadExcel("大数据导出测试.xlsx",response,workbook);    System.out.println("耗时:"+(new Date().getTime() - start.getTime())/1000+"秒");}

这里的最难的地方,就是接口IExcelExportServer的实现,底层会进行page++,不断的查找下一页,所以这里一定要有一段结束这个循环的逻辑。在实际项目中,更多的是查询的list的size()==0了。

page是从1开始的:

Ok,来看下导出的时间和导出的大小。

导出时间60秒左右,和刚刚的115秒,时间几乎少了一半。

导出的文件的大小,从原来的157M,变为了28M,少了6倍左右。

当然这个第一次的导出方式,文件的大小,也和导出的配置有关系,在之前为了解决图片导出问题,设置了为ExcelType.HSSF。

如果设置为ExcelType.XSSF的格式直接就OutOfMemoryError: GC overhead limit exceeded了(这种情况发生的原因是,程序基本上耗尽了所有的可用内存, GC也清理不了)。

总结

对于大数据的导出,核心要注意的就是内存溢出了。

(1)100万的数据,使用ExcelType.XSSF的方式导出,会报错:OutOfMemoryError: GC overhead limit exceeded。

(2)100万的数据,使用ExcelType. HSSF的方式导出,能导出,耗时115秒左右,导出的文件大小157M左右。

(3)大数据的导出方式,能导出,耗时60秒左右,导出的文件大小28M左右。

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

à悟纤学院:

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/A6ZagYTi

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

ShardingJDBC分库分表:http://t.cn/A6ZarrqS

分布式事务解决方案:http://t.cn/A6ZaBnIr

JVM内存模型调优实战:http://t.cn/A6wWMVqG

Spring入门到精通:https://t.cn/A6bFcDh4

大话设计模式之爱你:https://dwz.cn/wqO0MAy7


http://www.ppmy.cn/news/112525.html

相关文章

1.Python高频函数—数据合并merge()

前言 数据处理中经常对多个表的数据进行合并处理&#xff0c;python 提供两个十分好用的函数处理。merge() 、 concat() merger函数是Python里的数据分析工作中最常见的函数之一&#xff0c;主要应用场景是&#xff1a;针对同一个主键存在两张不同字段的表。&#xff08;这里强…

以太网 rx tx delay动态补丁测试

参考源码&#xff1a;x3399_nougat_industry 内核版本4.4 diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c old mode 100644 new mode 100755 index 44a3c2d..530c248 --- a/kernel/drivers/n…

udp_rx

timescale 1ns/1ns //////////////////////////////////////////////////////////////////////// // Author : EmbedFire // 实验平台: 野火FPGA系列开发板 // 公司 : http://www.embedfire.com // 论坛 : http://www.firebbs.cn // 淘宝 : https://fire-stm32.taob…

ALTLVDS TX ip和 ALTLVDS RX ip

1. ip core 应用场景 使用Intel FPGA自带的LVDS ip core进行电路板之间的串行数据收发以及并串、串并转换&#xff08;Serdes&#xff09;。 两块电路板之间相隔100m&#xff0c;使用双绞线作为传输介质&#xff0c;串行码流的速率为163.84Mbps&#xff0c;由于长距离传输中&a…

三线制PT100

关于恒压电阻桥三线制PT100的阻值计算 原理图计算思路 仿真计算测试代码 原理图 其中Rx1,Rx2,Rx3表示PT100三线的电阻&#xff0c;阻值相等Rx PT100阻值Rp 计算思路 1、设流过Rx1上电流I1&#xff0c;流过Rx2上电流I2 I1 (2V5REF-U1)/2000; I2 (2V5REF-U2)/2000;2、根据I1…

索尼黑卡RX100系列对比,RX100 M1\M2\M3\M4\M5\M6\M7

索尼黑卡RX100系列对比 索尼黑卡RX100系列定位&#xff1a;便携与高画质。 一、参数对比 配置/型号RX100 M1RX100 M2RX100 M3RX100 M4RX100 M5RX100 M6RX100 M7发布时间2012.62013.62014.52015.42016.102018.62019.7镜头焦段28 - 100mm24 - 70mm24 - 200mm光圈F1.8-4.8F1.8-…

网络知识:光纤收发器TX、RX介绍以及两者的区别

当我们远距离传输时&#xff0c;通常会使用光纤来传输。因为光纤的传输距离很远&#xff0c;一般来说单模光纤的传输距离在10千米以上&#xff0c;而多模光纤的传输距离最高也能达到2千米。而在光纤网络中&#xff0c;我们常常会使用到光纤收发器。那么光纤收发器怎么连?我们一…

测试吃鸡游戏帧数软件,帧数暴涨10%+ RX 560D开核“吃鸡”测试

说起开核&#xff0c;相信很多有资历的玩家都试过&#xff0c;掌握显卡开核技能可以说是DIY玩家从菜鸟走向老手的必经之路。而由于NVIDIA多采用物理方式彻底熔掉不良流处理器&#xff0c;所以开核这件事目前只能发生在A卡身上&#xff0c;因而很多富有DIY精神的玩家都会选择A卡…