解决java poi海量数据导出内存溢出问题

简介: 解决java poi海量数据导出导致内存溢出的问题

找了很多天的解决方法,一直被分页查询绕进去了,其实数据都能查出来的,真正卡的地方是ExcelExportUtil类下调错了方法。



最开始调用的方法是(标记的地方):  workbook = new HSSFWorkbook();和 workbook = new XSSFWorkbook();

这两个方法就是导出Excel的最关键的方法,接下来我来说说这两个方法作用:

1.HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls;

2.XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx;

对于不同版本的EXCEL文档要使用不同的工具类,如果使用错了,会提示如下错误信息。

org.apache.poi.openxml4j.exceptions.InvalidOperationException

org.apache.poi.poifs.filesystem.OfficeXmlFileException

当数据量超出65536条后,在使用HSSFWorkbook或XSSFWorkbook,程序会报OutOfMemoryError:Javaheap space;内存溢出错误。

而我们的数据量达到了9W条数据,用这两个方法肯定是报内存溢出的错误的。

最终我找到的解决方法是:从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的API----SXSSFWorkbook。

3.SXSSFWorkbook-来至官方的解释:实现“BigGridDemo”策略的流式XSSFWorkbook版本。这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行部分被保存在内存中。您可以提供用作书面数据基础的模板工作簿。有关详细信息,请参见https://poi.apache.org/spreadsheet/how-to.html#sxssf。请注意,仍然可能会消耗大量内存,这些内存基于您正在使用的功能,例如合并区域,注释......仍然只存储在内存中,因此如果广泛使用,可能需要大量内存。SXSSFWorkbook默认使用内联字符串而不是共享字符串表。这非常有效,因为没有文档内容需要保存在内存中,但也被称为制作与某些客户不兼容的文档。在启用共享字符串的情况下,文档中的所有唯一字符串必须保存在内存中。根据您的文档内容,这可能比共享字符串被禁用时使用更多的资源。在决定是否启用共享字符串之前,请仔细检查您的内存预算和兼容性需求。

而在poi架包中提供的方法用的是:


当数据量超过1000条时就会调用SXSSFWorkbook方法,从而解决了海量的数据导出会发生内存溢出的问题。

[java]  view plain  copy
  1. public void exportContacts(final PortalUserPage page, final HttpServletRequest request,  
  2.            final HttpServletResponse response) throws Exception {  
  3.   
  4.        final String name = "通讯录列表";  
  5.   
  6.        // 去掉分页  
  7.        page.setPage(1);  
  8.        page.setRows(Integer.MAX_VALUE);  
  9.        final List<CmssPortalUser> dataList = (List<CmssPortalUser>) this.queryPortalUserListWithGroup(page);  
  10.        final List<PortalUserExcelDto> userList = new ArrayList<>();  
  11.        for (final CmssPortalUser user : dataList) {  
  12.            final PortalUserExcelDto userDto = new PortalUserExcelDto();  
  13.            userDto.setIndex(user.getIndex() != null ? user.getIndex().toString() : "0");  
  14.            userDto.setRealName(user.getRealName());  
  15.            userDto.setCompany(user.getCompany());  
  16.            userDto.setCompanyBranch(user.getCompanyBranch());  
  17.            userDto.setDepartment(user.getDepartment());  
  18.            userDto.setTitle(user.getTitle());  
  19.            userDto.setPhone(user.getPhone());  
  20.            userDto.setLoginName(user.getLoginName());  
  21.            userDto.setProducts(user.getProducts());  
  22.            userDto.setEmail(user.getEmail());  
  23.            userDto.setGroup(user.getGroup());  
  24.            if (user.getOpenTime() != null) {  
  25.                // 开通时间日期格式化  
  26.                final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  27.                userDto.setOpenTime(format.format(user.getOpenTime()));  
  28.            }  
  29.            // 判断全局预览  
  30.            // 根据创建者ID查询该用户是否可以浏览全局  
  31.            user.setIfGlobelView(shareJedis.ifGlobelView(user.getId().longValue()) ? 1 : 0);  
  32.            if (user.getIfGlobelView() != null) {  
  33.                if (user.getIfGlobelView() == Constants.CURRENCY.ZERO) {  
  34.                    userDto.setIfGlobelView("否");  
  35.                }  
  36.                if (user.getIfGlobelView() == Constants.CURRENCY.ONE) {  
  37.                    userDto.setIfGlobelView("是");  
  38.                }  
  39.            }  
  40.            // 判断状态  
  41.            if (StringUtils.isNotBlank(user.getStatus())) {  
  42.                if (Constants.CONTACTS_STATUS.UNAVAILABILITY.equals(user.getStatus())) {  
  43.                    userDto.setStatus("停用");  
  44.                }  
  45.                if (Constants.CONTACTS_STATUS.AVAILABILITY.equals(user.getStatus())) {  
  46.                    userDto.setStatus("启用");  
  47.                }  
  48.            }  
  49.            // VIP类别  
  50.            userDto.setVipCategory(user.getVipCategoryName() != null ? user.getVipCategoryName() : null);  
  51.            // Vip级别  
  52.            userDto.setVipLevel(user.getVipLevelName() != null ? user.getVipLevelName() : null);  
  53.            // 判断短信通知  
  54.            if (user.getIsSendSms() != null) {  
  55.                if (Constants.UNIVERSAL_CONSTANT.ZERO.equals(user.getIsSendSms())) {  
  56.                    userDto.setIsSendSms("否");  
  57.                }  
  58.                if (Constants.UNIVERSAL_CONSTANT.ONE.equals(user.getIsSendSms())) {  
  59.                    userDto.setIsSendSms("是");  
  60.                }  
  61.            }  
  62.            userList.add(userDto);  
  63.        }  
  64.   
  65.        final ExportParams params = new ExportParams(name, name, ExcelType.XSSF);  
  66.        final Workbook workbook = ExcelExportUtil.exportExcel(params, PortalUserExcelDto.class, userList);  
  67.   
  68.        try {  
  69.            final String agent = request.getHeader("User-Agent").toLowerCase();  
  70.            // 开始下载文件  
  71.            final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
  72.            String filename = format.format(new Date().getTime()) + "-" + name + ".xlsx";  
  73.            if (!StringUtils.isEmpty(agent) && agent.contains("msie") || agent.contains("like gecko")  
  74.                    || (agent.indexOf("rv") > 0 && agent.indexOf("firefox") == -1)) {  
  75.                filename = URLEncoder.encode(filename, "UTF-8");  
  76.            } else {  
  77.                filename = new String(filename.getBytes("UTF-8"), "ISO8859-1");  
  78.            }  
  79.            response.setContentType("application/octet-stream");  
  80.   
  81.            response.setHeader("Content-Disposition""attachment;filename=".concat(filename));  
  82.   
  83.            final OutputStream out = response.getOutputStream();  
  84.            workbook.write(out);  
  85.            out.flush();  
  86.            out.close();  
  87.        } catch (final Exception e) {  
  88.            e.printStackTrace();  
  89.            log.error(e.getMessage());  
  90.        }  
  91.    }  

这部分代码是我所写的批量导出海量数据的部分代码,希望可以帮助和我遇到一样错误的人。
相关文章
|
12月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
1224 3
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
11月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
351 4
|
存储 缓存 Java
【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理
JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。
424 0
|
11月前
|
存储 缓存 Java
【深入浅出】揭秘Java内存模型(JMM):并发编程的基石
本文深入解析Java内存模型(JMM),揭示synchronized与volatile的底层原理,剖析主内存与工作内存、可见性、有序性等核心概念,助你理解并发编程三大难题及Happens-Before、内存屏障等解决方案,掌握多线程编程基石。
|
12月前
|
缓存 监控 Kubernetes
Java虚拟机内存溢出(Java Heap Space)问题处理方案
综上所述, 解决Java Heap Space溢出需从多角度综合施策; 包括但不限于配置调整、代码审查与优化以及系统设计层面改进; 同样也不能忽视运行期监控与预警设置之重要性; 及早发现潜在风险点并采取相应补救手段至关重要.
1113 17
|
Java 物联网 数据处理
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%
Java Solon v3.2.0 是一款性能卓越的后端开发框架,新版本并发性能提升700%,内存占用节省50%。本文将从核心特性(如事件驱动模型与内存优化)、技术方案示例(Web应用搭建与数据库集成)到实际应用案例(电商平台与物联网平台)全面解析其优势与使用方法。通过简单代码示例和真实场景展示,帮助开发者快速掌握并应用于项目中,大幅提升系统性能与资源利用率。
379 6
Java Solon v3.2.0 史上最强性能优化版本发布 并发能力提升 700% 内存占用节省 50%
|
监控 Kubernetes Java
最新技术栈驱动的 Java 绿色计算与性能优化实操指南涵盖内存优化与能效提升实战技巧
本文介绍了基于Java 24+技术栈的绿色计算与性能优化实操指南。主要内容包括:1)JVM调优,如分代ZGC配置和结构化并发优化;2)代码级优化,包括向量API加速数据处理和零拷贝I/O;3)容器化环境优化,如K8s资源匹配和节能模式配置;4)监控分析工具使用。通过实践表明,这些优化能显著提升性能(响应时间降低40-60%)同时降低资源消耗(内存减少30-50%,CPU降低20-40%)和能耗(服务器功耗减少15-35%)。建议采用渐进式优化策略。
696 2
|
缓存 监控 Cloud Native
Java Solon v3.2.0 高并发与低内存实战指南之解决方案优化
本文深入解析了Java Solon v3.2.0框架的实战应用,聚焦高并发与低内存消耗场景。通过响应式编程、云原生支持、内存优化等特性,结合API网关、数据库操作及分布式缓存实例,展示其在秒杀系统中的性能优势。文章还提供了Docker部署、监控方案及实际效果数据,助力开发者构建高效稳定的应用系统。代码示例详尽,适合希望提升系统性能的Java开发者参考。
680 4
Java Solon v3.2.0 高并发与低内存实战指南之解决方案优化