栏目分类
热点资讯
你的位置:ES中文网 > Plxyer中文网 > 基于EasyExcel实现百万级数据导入导出详解

Plxyer中文网

基于EasyExcel实现百万级数据导入导出详解

发布日期:2025-01-04 11:00    点击次数:151

在项目开发中往往需要使用到数据的导入和导出,导入就是从Excel中导入到DB中,而导出就是从DB中查询数据然后使用POI写到Excel上。 大数据的导入和导出,相信大家在日常的开发、面试中都会遇到。 很多问题只要这一次解决了,总给复盘记录,后期遇到同样的问题就好解决了。好啦,废话不多说开始正文! 1.传统POI的的版本优缺点比较 其实想到数据的导入导出,理所当然的会想到apache的poi技术,以及Excel的版本问题。 HSSFWorkbook 这个实现类是我们早期使用最多的对象,它可以操作Excel2003以前(包含2003)的所有Excel版本。在2003以前Excel的版本后缀还是.xls XSSFWorkbook 这个实现类现在在很多公司都可以发现还在使用,它是操作的Excel2003–Excel2007之间的版本,Excel的扩展名是.xlsx SXSSFWorkbook 这个实现类是POI3.8之后的版本才有的,它可以操作Excel2007以后的所有版本Excel,扩展名是.xlsx HSSFWorkbook 它是POI版本中最常用的方式,不过: 它的缺点是 最多只能导出 65535行,也就是导出的数据函数超过这个数据就会报错;它的优点是 不会报内存溢出。(因为数据量还不到7w所以内存一般都够用,首先你得明确知道这种方式是将数据先读取到内存中,然后再操作) XSSFWorkbook 优点:这种形式的出现是为了突破HSSFWorkbook的65535行局限,是为了针对Excel2007版本的1048576行,16384列,最多可以导出104w条数据;缺点:伴随的问题来了,虽然导出数据行数增加了好多倍,但是随之而来的内存溢出问题也成了噩梦。因为你所创建的book,Sheet,row,cell等在写入到Excel之前,都是存放在内存中的(这还没有算Excel的一些样式格式等等),可想而知,内存不溢出就有点不科学了!!! SXSSFWorkbook 从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的SXSSF方式: 优点: 这种方式不会一般不会出现内存溢出(它使用了硬盘来换取内存空间,也就是当内存中数据达到一定程度这些数据会被持久化到硬盘中存储起来,而内存中存的都是最新的数据),并且支持大型Excel文件的创建(存储百万条数据绰绰有余)。 缺点: 既然一部分数据持久化到了硬盘中,且不能被查看和访问那么就会导致,在同一时间点我们只能访问一定数量的数据,也就是内存中存储的数据;sheet.clone()方法将不再支持,还是因为持久化的原因;不再支持对公式的求值,还是因为持久化的原因,在硬盘中的数据没法读取到内存中进行计算;在使用模板方式下载数据的时候,不能改动表头,还是因为持久化的问题,写到了硬盘里就不能改变了; 2.使用方式哪种看情况 经过了解也知道了这三种Workbook的优点和缺点,那么具体使用哪种方式还是需要看情况的: 我一般会根据这样几种情况做分析选择: 1、当我们经常导入导出的数据不超过7w的情况下,可以使用 HSSFWorkbook 或者 XSSFWorkbook都行; 2、当数据量查过7w并且导出的Excel中不牵扯对Excel的样式,公式,格式等操作的情况下,推荐使用SXSSFWorkbook; 3、当数据量查过7w,并且我们需要操做Excel中的表头,样式,公式等,这时候我们可以使用 XSSFWorkbook 配合进行分批查询,分批写入Excel的方式来做; 3.百万数据导入导出 想要解决问题我们首先要明白自己遇到的问题是什么? 1、 我遇到的数据量超级大,使用传统的POI方式来完成导入导出很明显会内存溢出,并且效率会非常低; 2、 数据量大直接使用select * from tableName肯定不行,一下子查出来300w条数据肯定会很慢; 3、 300w 数据导出到Excel时肯定不能都写在一个Sheet中,这样效率会非常低;估计打开都得几分钟; 4、 300w数据导出到Excel中肯定不能一行一行的导出到Excel中。频繁IO操作绝对不行; 5、 导入时300万数据存储到DB如果循环一条条插入也肯定不行; 6、导入时300w数据如果使用Mybatis的批量插入肯定不行,因为Mybatis的批量插入其实就是SQL的循环;一样很慢。 解决思路: 针对1 : 其实问题所在就是内存溢出,我们只要使用对上面介绍的POI方式即可,主要问题就是原生的POI解决起来相当麻烦。 经过查阅资料翻看到阿里的一款POI封装工具EasyExcel,上面问题等到解决; 针对2: 不能一次性查询出全部数据,我们可以分批进行查询,只不过时多查询几次的问题,况且市面上分页插件很多。此问题好解决。 针对3: 可以将300w条数据写到不同的Sheet中,每一个Sheet写一百万即可。 针对4: 不能一行一行的写入到Excel上,我们可以将分批查询的数据分批写入到Excel中。 针对5: 导入到DB时我们可以将Excel中读取的数据存储到集合中,到了一定数量,直接批量插入到DB中。 针对6: 不能使用Mybatis的批量插入,我们可以使用JDBC的批量插入,配合事务来完成批量插入到DB。即 Excel读取分批+JDBC分批插入+事务。 3.1 模拟500w数据导出 需求:使用EasyExcel完成500w数据的导出。 500w数据的导出解决思路: 首先在查询数据库层面,需要分批进行查询(比如每次查询20w)每查询一次结束,就使用EasyExcel工具将这些数据写入一次;当一个Sheet写满了100w条数据,开始将查询的数据写入到另一个Sheet中;如此循环直到数据全部导出到Excel完毕。 ps:我们需要计算Sheet个数,以及循环写入次数。特别是最后一个Sheet的写入次数 因为你不知道最后一个Sheet会写入多少数据,可能是100w,也可能是25w因为我们这里的500w只是模拟数据,有可能导出的数据比500w多也可能少 ps:我们需要计算写入次数,因为我们使用的分页查询,所以需要注意写入的次数。 其实查询数据库多少次就是写入多少次 准备工作 1.基于maven搭建springboot工程,引入easyexcel依赖,这里我是用的时3.0版本 2.创建海量数据的sql脚本 3.实体类 4.vo类 导出核心代码 这是我电脑测试时内存占用和CPU使用情况,当然开了其他一些应用。 导出500w数据共计耗时,可以看到差不多400s左右,当然还要考虑业务复杂度已经电脑配置,我这里只是一个导出的demo并不涉及其他业务逻辑,在实际开发中可能时间会比这个更长一些 看下导出效果,我上面的脚本向插入了500w数据,100w一个sheet因此正好五个 3.2模拟500w数据导入 500W数据的导入解决思路 1、首先是分批读取读取Excel中的500w数据,这一点EasyExcel有自己的解决方案,我们可以参考Demo即可,只需要把它分批的参数5000调大即可。 2、其次就是往DB里插入,怎么去插入这20w条数据,当然不能一条一条的循环,应该批量插入这20w条数据,同样也不能使用Mybatis的批量插入语,因为效率也低。 3、使用JDBC+事务的批量操作将数据插入到数据库。(分批读取+JDBC分批插入+手动事务控制) 代码实现 controller层测试接口 Excel导入事件监听 核心业务代码 jdbc工具类 druid.properties配置文件 这里我将文件创建在类路径下,需要注意的是连接mysql数据库时需要指定rewriteBatchedStatements=true批处理才会生效,否则还是逐条插入效率较低,allowMultiQueries=true表示可以使sql语句中有多个insert或者update语句(语句之间携带分号),这里可以忽略。 测试结果 ------开始读取Excel的Sheet时间(包括导入数据过程):1674181403555ms------200000条,开始导入到数据库时间:1674181409740ms2023-01-20 10:23:29.943  INFO 18580 --- [nio-8888-exec-1] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited200000条,结束导入到数据库时间:1674181413252ms200000条,导入用时:3512ms200000条,开始导入到数据库时间:1674181418422ms200000条,结束导入到数据库时间:1674181420999ms200000条,导入用时:2577ms.....200000条,开始导入到数据库时间:1674181607405ms200000条,结束导入到数据库时间:1674181610154ms200000条,导入用时:2749ms------结束读取Excel的Sheet时间(包括导入数据过程):1674181610155ms------------读取Excel的Sheet时间(包括导入数据)共计耗时:206600ms------ 这里我删除里部分日志,从打印结果可以看出,在我的电脑上导入500w数据差不多需要20多秒的时间,还是很快的。当然公司的业务逻辑很复杂,数据量也比较多,表的字段也比较多,导入和导出的速度会比现在测试的要慢一点。 4.总结 1.如此大批量数据的导出和导入操作,会占用大量的内存实际开发中还应限制操作人数。 2.在做大批量的数据导入时,可以使用jdbc手动开启事务,批量提交。 以上就是基于EasyExcel实现百万级数据导入导出详解的详细内容,更多关于EasyExcel数据导入导出的资料请关注脚本之家其它相关文章!