POI玩儿不动Excel百万级别数据导入导出,如何优化?EasyExcel+解决方案

679 阅读3分钟

真实场景: 大家在日常的开发中,excel导入导出是非常常见的需求,大部分公司因为业务量比较小,操作的数据量都是几千、几万,这个级别的数据量。我们采用Apache的POI很轻松可以搞定,但如果遇到大型互联网公司动不动就百万级别的用户体量,POI就会出现各种各样的问题,比较常见的现象就是内存OOM或者导出耗时特别久无响应,很显然,POI在百万级别的数据量处理,已经不合适了。那有没有什么好的解决方案能够有效的支撑百万级别的数据导入导出,而且系统的CPU、内存等核心指标不会出现明显波动呢?答案是肯定的

导入百万级别数据excel到MySQL,有什么痛点呢?

1. 一次加载百万级别数据到内存,发生OOM;

2. 导入时百万级别数据存储到MySQL如果循环一条条插入,数据库链接不够用;

导出百万级别数据MySQL到excel,有什么痛点?

1. 一次查询百万级别数据到内存,mybatis查询超时报错;

2. 用一次加载百万级别数据到内存,发生OOM;

3. 百万级别数据导出到Excel,写到一个Sheet中,能打开,会卡爆;

4. 百万级别数据导出到Excel中一行一行写入Excel,频繁io操作,CPU飙高;

业务操作高峰期,后台管理员频繁操作导入导出excel,这个时候系统很容易就会因为内存溢出挂掉了

解决方案*

01

弃用POI,选用EasyExcel开源

EasyExcel教程:

网址:easyexcel.opensource.alibaba.com/

02

百万级别导入方案

1. 逐行解析excel数据,分批读取excel数据放到list,list达到一定数据量持久化到DB,同时清空list列表数据;

2. 采用mybatis的foreach批量保存、mybatis plus批量saveBatch方法保存、spring jdbcTemplate,不过记得配置连接池参数要加上rewriteBatchedStatements=true

03

百万级别导出方案

1. 分批分页查询db数据到内存,比如一次查询5000条,分20次分批查询出来;

2. 每次加载指定大小的数据到内存,比如每次5000条,5000条批量写入到excel以后,清空当前list,释放内存;

3. 分多个sheet写入,每个sheet比如放20w,100百万数据放到5个sheet;

4. 每次从数据库批量读取指定大小的数据写入到excel,比如每次5000条;

04

解决高峰期导入导出资源瓶颈

1. 从产品侧设计的时候,引导产品,将导入导出功能设计成异步,尽量不要同步等待,虽然牺牲了一点体验,但是长期看对系统的稳定非常重要。(为了产品的体验,可以提供一个统一excel导入导出历史记录功能给产品或运营同学,支持查看对应的下载进度,可追溯);

2. 前端导入导出按钮控制操作的频率,比如10分钟内不能频繁导入导出;

3. 后端导入导出采用MQ异步排队处理,防止把内存写爆,CPU打满;

4. 采用动态配置开关控制导入导出的数量,通过压测预估系统处理数据的阈值默认配置一个,导入导出超过阈值需要产品或运营发邮件申请,开发修改配置,如果业务确实有超大数据量要求,超过阈值太多,引导产品或运营分批导入导出解决;