Java 使用 Easyexcel 导出大量数据

读Excel | Easy Excel

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.基于maven搭建springboot工程,引入easyexcel依赖,这里我是用的时3.0版本

   <!--EasyExcel相关依赖--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.0.5</version></dependency>

2.创建海量数据的sql脚本

CREATE TABLE dept( /*部门表*/
deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0,
dname VARCHAR(20)  NOT NULL  DEFAULT "",
loc VARCHAR(13) NOT NULL DEFAULT ""
) ;#创建表EMP雇员
CREATE TABLE emp
(empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/
ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/
job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/
mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/
hiredate DATE NOT NULL,/*入职时间*/
sal DECIMAL(7,2)  NOT NULL,/*薪水*/
comm DECIMAL(7,2) NOT NULL,/*红利*/
deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/
) ;#工资级别表
CREATE TABLE salgrade
(
grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
losal DECIMAL(17,2)  NOT NULL,
hisal DECIMAL(17,2)  NOT NULL
);#测试数据
INSERT INTO salgrade VALUES (1,700,1200);
INSERT INTO salgrade VALUES (2,1201,1400);
INSERT INTO salgrade VALUES (3,1401,2000);
INSERT INTO salgrade VALUES (4,2001,3000);
INSERT INTO salgrade VALUES (5,3001,9999);delimiter $$#创建一个函数,名字 rand_string,可以随机返回我指定的个数字符串
create function rand_string(n INT)
returns varchar(255) #该函数会返回一个字符串
begin
#定义了一个变量 chars_str, 类型  varchar(100)
#默认给 chars_str 初始值   'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'declare chars_str varchar(100) default'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; declare return_str varchar(255) default '';declare i int default 0; while i < n do# concat 函数 : 连接函数mysql函数set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));set i = i + 1;end while;return return_str;end $$#这里我们又自定了一个函数,返回一个随机的部门号
create function rand_num( )
returns int(5)
begin
declare i int default 0;
set i = floor(10+rand()*500);
return i;
end $$#创建一个存储过程, 可以添加雇员
create procedure insert_emp(in start int(10),in max_num int(10))
begin
declare i int default 0;
#set autocommit =0 把autocommit设置成0#autocommit = 0 含义: 不要自动提交set autocommit = 0; #默认不提交sql语句repeatset i = i + 1;#通过前面写的函数随机产生字符串和部门编号,然后加入到emp表insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());until i = max_numend repeat;#commit整体提交所有sql语句,提高效率commit;end $$#添加8000000数据
call insert_emp(100001,8000000)$$#命令结束符,再重新设置为;
delimiter ;

3.实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp implements Serializable {@ExcelIgnoreprivate Integer empno;@ExcelProperty(value = "员工名称")private String ename;@ExcelProperty(value = "工作")private String job;@ExcelProperty(value = "主管编号")private Integer mgr;@ExcelProperty(value = "入职日期")private Date hiredate;@ExcelProperty(value = "薪资")private BigDecimal sal;@ExcelProperty(value = "奖金")private BigDecimal comm;@ExcelProperty(value = "所属部门")private Integer deptno;}

4.vo类
@Data
public class EmpVo {@ExcelIgnoreprivate Integer empno;@ExcelProperty(value = "员工名称")private String ename;@ExcelProperty(value = "工作")private String job;@ExcelProperty(value = "主管编号")private Integer mgr;@ExcelProperty(value = "入职日期")private Date hiredate;@ExcelProperty(value = "薪资")private BigDecimal sal;@ExcelProperty(value = "奖金")private BigDecimal comm;@ExcelProperty(value = "所属部门")private Integer deptno;}

5、导出核心代码

@Resource
private EmpService empService;
/*** 分批次导出*/
@GetMapping("/export")
public void export() throws IOException {Long startTime = System.currentTimeMillis();empService.export(); //导出Long endTime = System.currentTimeMillis();Long elapsedTime = (endTime - startTime) / 1000;System.out.println("导出_方式耗时:" + elapsedTime + "s");}
public class ExcelConstants {//一个sheet装100w数据public static final Integer PER_SHEET_ROW_COUNT = 1000000;//每次查询20w数据,每次写入20w数据public static final Integer PER_WRITE_ROW_COUNT = 200000;
}

实现类中:
@Override
public void export() throws IOException {OutputStream outputStream =null;try {//记录总数:实际中需要根据查询条件进行统计即可     Integer totalCount = empMapper.selectCount(null);//每一个Sheet存放100w条数据Integer sheetDataRows = ExcelConstants.PER_SHEET_ROW_COUNT;//每次写入的数据量20w,每页查询20WInteger writeDataRows = ExcelConstants.PER_WRITE_ROW_COUNT;//计算需要的Sheet数量Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);//计算一般情况下每一个Sheet需要写入的次数(一般情况不包含最后一个sheet,因为最后一个sheet不确定会写入多少条数据)Integer oneSheetWriteCount = sheetDataRows % writeDataRows == 0 ? (sheetDataRows / writeDataRows) : (sheetDataRows / writeDataRows + 1);//计算最后一个sheet需要写入的次数Integer lastCountAll = totalCount - (sheetNum-1)*sheetDataRows;Integer lastSheetWriteCount = lastCountAll % writeDataRows == 0 ? (lastCountAll / writeDataRows) : (lastCountAll / writeDataRows + 1);ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletResponse response = requestAttributes.getResponse();outputStream = response.getOutputStream();//必须放到循环外,否则会刷新流ExcelWriter excelWriter = EasyExcel.write(outputStream).build();//开始分批查询分次写入for (int i = 0; i < sheetNum; i++) {//创建SheetWriteSheet sheet = new WriteSheet();sheet.setSheetName("测试Sheet1"+i);sheet.setSheetNo(i);//循环写入次数: j的自增条件是当不是最后一个Sheet的时候写入次数为正常的每个Sheet写入的次数,如果是最后一个就需要使用计算的次数lastSheetWriteCountfor (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {//分页查询一次20wPage<Emp> page = empMapper.selectPage(new Page(j + 1 + oneSheetWriteCount * i, writeDataRows), null);List<Emp> empList = page.getRecords();//使用pagehelper的如下
// int  pageNum = j + 1 + oneSheetWriteCount * i;                    //PageHelper.startPage(pageNum,writeDataRows,getOrderBy(pageable.getSort())).setReasonable(true);
//List<DqtbsHiddenDangerQuery> list = mapper.expmortByPage(dto);//封装成可以导出实体类List<EmpVo> empVoList = new ArrayList<>();for (Emp emp : empList) {EmpVo empVo = new EmpVo();BeanUtils.copyProperties(emp, empVo);empVoList.add(empVo);}WriteSheet writeSheet = EasyExcel.writerSheet(i, "员工信息" + (i + 1)).head(EmpVo.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();//写数据excelWriter.write(empVoList, writeSheet);}}// 下载EXCELresponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止浏览器端导出excel文件名中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("员工信息", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");excelWriter.finish();outputStream.flush();} catch (IOException e) {e.printStackTrace();} catch (BeansException e) {e.printStackTrace();}finally {if (outputStream != null) {outputStream.close();}}
}

前端vue的:

  //导出exportExcel(values) {let this_ = thisthis_.spinningExport = truethis.$api.export(BASE_URL + 'exportNew', values, `数据查询_${moment(new Date()).format('YYYY-MM-DD')}.xlsx`, {success() {this_.spinningExport = false},fail() {this_.spinningExport = false}})},

分批量查询,例如,一个sheet 页 存储 10000条,分页每次查1000条,每个sheet需要查10次。总数据50000条,就分了5个sheet页来显示,大批量数据来说,easyExcel还是很好用的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/102406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇腾910使用记录

一. 压缩文件和解压文件 1. 压缩文件 tar -czvf UNITE-main.tar.gz ./UNITE-main/2. 解压文件 tar -xvf ./UNITE-main/二. CUDA更改为NPU data[label] data[label].cuda() data[instance] data[instance].cuda() data[image] data[image].cuda()更改为 data[label] da…

小程序中使用echarts的相关配置以及折线图案例(简单易懂)

第一步&#xff1a;引入echarts文件--此文件需要下载&#xff1a; 下载地址&#xff1a;点击此处进行下载echarts文件 点击Download ZIP下载压缩包&#xff0c;注意&#xff1a;e-canvas是我从完整的文件中剥离出来的有用的&#xff0c;不会影响项目。 第二步&#xff1a;把整…

ctfshow萌新计划web9-14(正则匹配绕过)

目录 web9 web10 web11 web12 web13 web14 web9 审一下代码&#xff0c;需要匹配到system|exec|highlight才会执行eval函数 先看一下当前目录下有什么 payload&#xff1a;?csystem(ls); index.php是首页&#xff0c;我们看看config.php payload&#xff1a;?csystem…

nodejs+vue+elementui医院挂号预约管理系统4n9w0

前端技术&#xff1a;nodejsvueelementui 前端&#xff1a;HTML5,CSS3、JavaScript、VUE 1、 node_modules文件夹(有npn install Express 框架于Node运行环境的Web框架, 开发语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff…

邮政编码,格式校验:@ZipCode(自定义注解)

目标 自定义一个用于校验邮政编码格式的注解ZipCode&#xff0c;能够和现有的 Validation 兼容&#xff0c;使用方式和其他校验注解保持一致&#xff08;使用 Valid 注解接口参数&#xff09;。 校验逻辑 有效格式 不能包含空格&#xff1b;应为6位数字&#xff1b; 不校验…

AI「鸟口普查」,康奈尔大学利用深度学习分析北美林莺分布

据世界自然基金会统计&#xff0c;1970-2016 年&#xff0c;全球代表物种种群数量减少了 68%&#xff0c;生物多样性不断下降。 保护生物多样性&#xff0c;需要对当地生态情况进行准确分析&#xff0c;制定合理的生态保护政策。然而&#xff0c;生态数据太过庞杂&#xff0c;统…

瀑布流布局(CSS flex实现)

关键点 使用了 vw 进行自适应缩放html: <div class="container"><div class="queue"><div

小程序中如何设置所服务地区的时区

在全球化的背景下&#xff0c;小程序除了在中国使用外&#xff0c;还为海外的华人地区提供服务。例如我们采云小程序为泰国、阿根廷、缅甸等国家的商家就提供过微信小程序。这些商家开通小程序&#xff0c;为本地的华人提供服务。但通常小程序的开发者/服务商位于中国&#xff…

蓝桥等考Python组别十七级006

第一部分:选择题 1、Python L17 (15分) 运行下面程序,输出的结果是( )。 def func(x, y): return (x - y) // 2 print(func(11, 4)) 2345正确答案:B 2、Python L17 (15

【MySQL】联合查询、子查询、合并查询

这里提供了三个表&#xff1a; 表1&#xff1a; mysql> select * from class; -------------- | id | name | -------------- | 1 | 一班 | | 2 | 二班 | | 3 | 三班 | -------------- 3 rows in set (0.01 sec) 表2&#xff1a; mysql> select * fro…

TCP/IP(十四)流量控制

一 流量控制 说明&#xff1a; 本文只是原理铺垫,没有用tcpdumpwiresahrk鲜活的案例讲解,后续补充 ① 基本概念 流量控制: TCP 通过接受方实际能接收的数据量来控制发送方的窗口大小 ② 正常传输过程 背景:1、客户端是接收方,服务端是发送方 --> 下载2、假设接收窗…

【0227】smgr设计机制之新建一个磁盘表文件

相关阅读: 【0222】存储管理器smgr设计机制,及SMgrRelation、SMgrRelationData的作用(1) 【0223】源码剖析smgr底层设计机制(3) 【0224】smgr设计机制之通过RelFileNode访问磁盘表文件(2) 【0225】源码分析postgres磁盘块(disk block)定义 【0226】smgr设计机制中,s…

OpenCV4(C++)——模板匹配

matchTemplate 模板匹配和卷积运算大致相同&#xff0c;模板图类似于卷积核&#xff0c;从原图的左上角开始进行滑动窗口的操作&#xff0c;最后得到一个特征图&#xff0c;这个特征图里的数值就是每次计算得到的相似度&#xff0c;通用匹配方式&#xff0c;相似值是&#xff…

强制结束subprocess.Popen开启的任务

强制结束subprocess.Popen开启的任务 需要使用到psutil库&#xff0c;可以通过pip安装 import subprocessimport psutildef kill(proc_pid):process psutil.Process(proc_pid)for proc in process.children(recursiveTrue):proc.kill()process.kill()proc subprocess.Popen([…

浅谈高速公路服务区分布式光伏并网发电

前言 今年的国家经济工作会议提出&#xff1a;将“做好碳达峰、碳中和工作”作为 2021年的主要任务之一&#xff0c;而我国高速公路里程 15.5万公里&#xff0c;对能源的需求与日俱增&#xff0c;碳排放量增速明显。 为了实现采用减少碳排放量&#xff0c;采用清洁能源替代的…

【Java 进阶篇】JavaScript 与 HTML 的结合方式

JavaScript是一种广泛应用于Web开发中的脚本语言&#xff0c;它与HTML&#xff08;Hypertext Markup Language&#xff09;结合使用&#xff0c;使开发人员能够创建交互式和动态的网页。在这篇博客中&#xff0c;我们将深入探讨JavaScript与HTML的结合方式&#xff0c;包括如何…

第一个 Python 程序

三、第一个 Python 程序 好了&#xff0c;说了那么多&#xff0c;现在我们可以来写一下第一个 Python 程序了。 一开始写 Python 程序&#xff0c;个人不太建议用专门的工具来写&#xff0c;不方便熟悉语法&#xff0c;所以这里我先用 Sublime Text 来写&#xff0c;后期可以…

RobotFramework自动化测试框架的基础关键字

1.1.1 如何搜索RobotFramework的关键字 有两种方式可以快速的打开RIDE的关键字搜索对话框 1、选择菜单栏Tools->Search Keywords&#xff0c;然后会出现如下的关键字搜索对话框&#xff0c;这个对话框就类似提供了一个关键字的API的功能&#xff0c;提供了关键字的…

如何建立线上线下相结合的数字化新零售体系?

身处今数字化时代&#xff0c;建立线上线下相结合的数字化新零售体系是企业成功的关键。蚓链数字化营销系统致力于帮助企业实现数字化转型&#xff0c;打通线上线下销售渠道&#xff0c;提升品牌影响力和用户黏性&#xff0c;那么具体是如何建立的&#xff1f; 1. 搭建数字化中…

P1886 滑动窗口 /【模板】单调队列

题目&#xff1a; P1091 [NOIP2004 提高组] 合唱队形 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) n 位同学站成一排&#xff0c;音乐老师要请其中的 &#xfffd;−&#xfffd;n−k 位同学出列&#xff0c;使得剩下的 &#xfffd;k 位同学排成合唱队形。 合唱队形是指这…