Excel百万级数据导入导出方案

本文使用EasyExcel工作,导出格式XLSX

1.生成测试数据

这里用到的是MYSQL 5.7.31 创建表语句

CREATE TABLE `ACT_RESULT_LOG` (`onlineseqid` int(11) NOT NULL AUTO_INCREMENT,`businessid` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`becifno` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`ivisresult` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`createdby` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`createddate` datetime DEFAULT CURRENT_TIMESTAMP,`updateby` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,`updateddate` datetime DEFAULT CURRENT_TIMESTAMP,`risklevel` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,PRIMARY KEY (`onlineseqid`)
) ENGINE=InnoDB AUTO_INCREMENT=1310694 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

这里插入测试数据

INSERT INTO `wjb`.`ACT_RESULT_LOG` (`onlineseqid`, `businessid`, `becifno`, `ivisresult`, `createdby`, `createddate`, `updateby`, `updateddate`, `risklevel`) VALUES (18179, 'test-01', '测试excel百万级数据导入导出', 'YES', '=======', '2022-10-11 10:18:11', 'wujubin', '2022-10-11 10:18:11', '1');-- 重复执行这条sql 一直执行数量大于100w 这里要注意了如果使用单个sheet 数据不能大于104w 这是excel的限制
INSERT INTO ACT_RESULT_LOG(`businessid`, `becifno`, `ivisresult`, `createdby`, `createddate`, `updateby`, `updateddate`, `risklevel`)
select `businessid`, `becifno`, `ivisresult`, `createdby`, `createddate`, `updateby`, `updateddate`, `risklevel` from ACT_RESULT_LOG

2.导出数据

依赖导入

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version>
</dependency>

导出注意点

  • 一般需求导出excel数据量都比较少,不会引起OOM,因为数据都是放到内存中,如果达到百万级别很容易出现OOM,这里可以使用分页查询来处理。
  • 如果数据量超过104w,就要写到多个sheet中,本文演示单个sheet导入导出百万数据
不分页查询导出
@GetMapping("/download")public void download(HttpServletResponse response) throws IOException {log.info("start====>{}",System.currentTimeMillis());long l = System.currentTimeMillis();// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postmanresponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), ActResultLogModel.class).sheet("模板").doWrite(actResultLogService.getList());log.info("end====>{}",System.currentTimeMillis()-l);}

结果耗时:40s. 但是很容易导致OOM,这里我设置的jvm内存比较大【不推荐】

分页查询导出
 @GetMapping("/download2")public void download2(HttpServletResponse response) throws IOException {log.info("start====>{}",System.currentTimeMillis());long l = System.currentTimeMillis();OutputStream outputStream = null;try {outputStream = response.getOutputStream();ExcelWriter excelWriter = EasyExcel.write(outputStream, ActResultLogModel.class).build();// 这里注意 如果同一个sheet只要创建一次WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();// 导出总数量int dataCount = actResultLogService.getDataCount();// 每次查询sizeint count = 200000;// 计算查询次数/页数int index = dataCount>count?dataCount/count+1:1;// 根据数据库分页的总的页数来for (int i = 0; i < index; i++) {List<ActResultLogModel> listByPage = actResultLogService.getListByPage(i*count,  count);log.info("===>i:{},size:{}",(i+1),listByPage.size());excelWriter.write(listByPage, writeSheet);}}catch (Exception e){log.error("====>{}",e.getMessage());}// 这里注意 使用swagger 会导致各种问题,请直接用浏览器或者用postmanresponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("测试", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");log.info("end====>{}",System.currentTimeMillis()-l);}

耗时:37s. 不会导致OOM,且速度还要快些

导出的数据

3.导入数据

处理思路:导入文件后解析时需要分批操作【也是防止大量数据进入内存,导致OOM

这里演示解析数据后,分批入库。入库也可换做做业务

这里需要了解一个点,easyExcel在解析excel的时候提供了一个监听器,只要实现它,读每行内容之后都会执行invoke方法

@Slf4j
public class UploadDataListener implements ReadListener<ActResultLogModel> {/*** 每隔BATCH_COUNT条存储数据库,实际使用中可以根据MYSQL服务器配置来配置,调试最优执行SQL大小,* 然后清理list,方便内存回收*/private static final int BATCH_COUNT = 50000;private List<ActResultLogModel> actResultLogModelList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);/*** 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。*/private final ActResultLogService actResultLogService;//如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来public UploadDataListener(ActResultLogService actResultLogService){this.actResultLogService = actResultLogService;}//这个每一条数据解析都会来调用@Overridepublic void invoke(ActResultLogModel actResultLogModel, AnalysisContext analysisContext) {actResultLogModelList.add(actResultLogModel);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (actResultLogModelList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listactResultLogModelList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}//所有数据解析完成了 都会来调用@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {saveData();log.info("===>解析完成!!");}//存储数据库public void saveData(){int i = actResultLogService.saveList(actResultLogModelList);log.info("====>{}",i);}
}

其中在配置分批次入库时,BATCH_COUNT参数设置需要根据MYSQL服务器配置来,过大可能会报You can change this value on the server by setting the ‘max_allowed_packet’ variable。设置MYSQL中配置文件my.cnf的max_allowed_packet参数就行,大于你报错提示的size就行。

其他具体代码

@PostMapping("/upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {log.info("start====>{}",System.currentTimeMillis());long l = System.currentTimeMillis();EasyExcel.read(file.getInputStream(), ActResultLogModel.class, new UploadDataListener(actResultLogService)).sheet().doRead();    // 这里初始化监听器就可以了log.info("end====>{}",System.currentTimeMillis()-l);return "success";
}
// 写入数据
public int saveList(List<ActResultLogModel> actResultLogModelList){// 最好判断 可能会报if (CollectionUtils.isEmpty(actResultLogModelList)) return -1;int i = actResultLogMapper.insertData(actResultLogModelList);log.info("数据入库数量:====>{}",i);return i;
}
// 分批入库@Insert({"<script>" +"<foreach collection=\"actResultLogModelList\" item=\"item\" separator=\";\">" +"INSERT INTO `wjb`.`ACT_RESULT_LOG2` (`businessid`, `becifno`, `ivisresult`, `createdby`, `createddate`, `updateby`, `updateddate`, `risklevel`) " +" VALUES (#{item.businessid}, #{item.becifno}, #{item.ivisresult}, #{item.createdby}, #{item.createddate}, #{item.updateby}, #{item.updateddate}, #{item.risklevel})" +"</foreach>" +"</script>"})int insertData(@Param("actResultLogModelList") List<ActResultLogModel> actResultLogModelList);

主要注意:OOM,根据服务器JVM大小来处理对于数据量

其他更多玩法:EasyExcel官方文档

Excel导入导出百万级数据相关推荐

  1. Excel怎么导出百万级数据

    以前很久没碰到导出上10万数据到Excel.最近两年的业务有导出几十万数据的场景.Excel导出之前一直用NPOI导出的,NPOI的优势是不依赖Office环境.但是早期的NPOI导出操作Excel全 ...

  2. oracle百万级数据导入,用Perl从oracle导出百万级数据到excel

    Perl从oracle导出百万级数据到excel excel 2007 可以存放1048576行.16384列的数据:excel 2003大概是65535行 我从oracle中导出30万行60列的数据 ...

  3. 使用POI导出百万级数据到excel的解决方案

    使用POI导出百万级数据到excel的解决方案 参考文章: (1)使用POI导出百万级数据到excel的解决方案 (2)https://www.cnblogs.com/hxun/p/11419006. ...

  4. php导出1万条数据excel_PHP快速导出百万级数据到CSV或者EXCEL文件

    前言: 很多时候,因为数据统计,我们需要将数据库的数据导出到Excel等文件中,以供数据人员进行查看,如果数据集不大,其实很容易:但是如果对于大数集的导出,将要考虑各种性能的问题,这里以导出数据库一百 ...

  5. 根据实体excel导入导出百万数据,可修改表头名称

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 表格导入导出实现效果展示 根据实体类导出模板 读取表格数据 导出数据为excel 进阶:修改表格导出的列头 controll ...

  6. 百万excel导入mysql_百万级xlsx表格导入数据库的实现方案

    需求是这样的,供应商给到一份 xlsx 表格(144MB),里面刚好有 100w 行数据(11列).我需要把它们稍作处理后写入到 mysql 数据库 项目基于 Laravel,既然需要稍作处理,那我首 ...

  7. php oracle打印输出,php 连接oracle 导出百万级数据

    1,我们一般做导出的思路就是,根据我们想要的数据,全部查询出来,然后导出来,这个对数据量很大的时候会很慢,这里我提出来的思想就是分页和缓冲实现动态输出. 2.普通的我就不说了,下面我说一下分页和内存刷 ...

  8. kettle分批处理大表数据_Kettle大量数据快速导出的解决方案(利用SQL导出百万级数据,挺快的)...

    org.apache.commons commons-vfs2 2.0 org.scannotation scannotation 1.0.3 dom4j dom4j 1.6.1 pentaho-ke ...

  9. php导出1万条数据excel_实用!用PHP导出百万级大数据到Excel

    实用!用PHP导出百万级大数据到Excel 作者:PHPYuan 时间:2018-07-31 03:41:41 关注我们的人 月薪都过万了 一.数据量分析 假设我们需要单日导入的数量为20W+ Exc ...

最新文章

  1. [译]Vulkan教程(04)基础代码
  2. 破天荒第一遭 安全公司因玩忽职守被客户告上法庭
  3. java编译器代码检查_java 命名代码检查-注解处理器
  4. WinCE 控制面板的创建
  5. NeurIPS2021 HRFormer:HRNet又出续作啦!国科大北大MSRA提出高分辨率Transformer,开源!...
  6. MySql之sql语句(自用)
  7. web server linux,GitHub - markparticle/WebServer: C++ Linux WebServer服务器
  8. 基金登记过户系统相关
  9. python模拟用户数据
  10. VSCode摸鱼插件,让工作更轻松
  11. itools苹果录屏大师_录屏大师限免|2019年1月最后一次苹果精选限时免费App 0131...
  12. 通过分析双色球历史中奖数据-增加机选号码中奖概率
  13. 中国出海50强,华为超越阿里得亚军,第一名居然是它?
  14. 考取FRM证书的三大好处,可能你还不知道
  15. c语言模拟走迷宫课程程序设计报告,《C语言程序设计》走迷宫游戏程序设计.doc...
  16. 宴会泡泡机市场前景分析及研究报告
  17. 解决Qualcomm Atheros QCA8172 有线网卡驱动问题
  18. 玩转 uniapp 全端开发
  19. PHY6252国产低功耗蓝牙5.2 SoC芯片智能手环/智能家居方案替代NRF52810
  20. 高仿糗事百科,完整版项目源码,带服务器部分

热门文章

  1. ppt怎么插入html代码,如何在PPT中插入html网.ppt
  2. 成都最最最牛逼的IT公司全在这了,来成都一起造富。。。
  3. SpringBoot全局异常处理
  4. 不论你技术多牛,这13条职场“潜规则”,越早知道越好!
  5. 畅游电驴/电骡(emule) 1.0 发布-下载网络资源的利器
  6. 【计量经济学导论】04. 多重共线性
  7. 城市公共交通周 9月18日郑州5条公交免费坐
  8. unity3D游戏开发十之粒子系统
  9. 新款文章,绝无仅有!微信语音aud文件转换为mp3格式
  10. JavaWeb-狂神系列