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还是很好用的。
相关文章:
Java 使用 Easyexcel 导出大量数据
读Excel | Easy Excel 1、 我遇到的数据量超级大,使用传统的POI方式来完成导入导出很明显会内存溢出,并且效率会非常低;2、 数据量大直接使用select * from tableName肯定不行,一下子查出来300w条数据肯定会很慢;3、 …...

高效防汛决策:山海鲸可视化系统助力城市防洪
随着全球气候的变化,自然灾害如洪水、台风等频发,防范洪水成为城市管理者和居民们亟待解决的重要问题。 洪水的威胁 洪水是自然界的杀手之一,不仅会造成大量的财产损失,还可能危害人们的生命安全。因此,预测、监测和有…...

易点云CFO向征:CFO不能只讲故事,价值创造才是核心
作者 | 曾响铃 文 | 响铃说 在今年6月初,也是易点云上市6天后,《巴伦周刊》正式启动评价“2023港美上市中国企业CFO精英100”的活动。 时间来到9月,评价揭秘,易点云CFO向征成功入选,被评为“年度最具成长潜力CFO”…...

【计算机网络】poll | epoll
文章目录 1. pollpoll函数参数解析代码解析PollServer代码 poll 特点 2. epoll认识接口epoll_createepoll_ctlepoll_wait 基本原理红黑树就绪队列 1. poll poll函数参数解析 输入 man poll poll的第一个参数是文件描述符 poll的第二个参数为 等待的多个文件描述符(fd)数字层面…...

C++设计模式_07_Bridge 桥模式
文章目录 1. 动机(Motivation)2. 代码演示Bridge 桥模式2.1 基于继承的常规思维处理2.2 基于组合关系的重构优化2.3 采用Bridge 桥模式的实现 3. 模式定义4. 结构(Structure)5. 要点总结 与上篇介绍的Decorator 装饰模式一样&…...
[JAVA版本] Websocket获取B站直播弹幕——基于直播开放平台
教程 B站直播间弹幕Websocket获取 — 哔哩哔哩直播开放平台 基于B站直播开放平台开放且未上架时,只能个人使用。 代码实现 1、相关依赖 fastjson2用于解析JSON字符串,可自行替换成别的框架。 hutool-core用于解压zip数据,可自行替换成别的…...

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

广告牌安全监测,保障户外广告牌的安全与稳定
随着城市的发展和现代化,广告牌已经成为城市风景的一部分。然而,随之而来的是广告牌安全问题,因为它们暴露在各种天气和环境条件下,一旦掉落,可能对人们的生命和财产造成威胁。广告牌安全监测有效的解决了这一问题&…...

分类预测 | MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单元数据分类预测
分类预测 | MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单元数据分类预测 目录 分类预测 | MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单元数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单…...

进来了解实现官网搜索引擎的三种方法
做网站的目的是对自己的品牌进行推广,让越来越多的人知道自己的产品,但是如果只是做了一个网站放着,然后等着生意找上门来那是不可能的。在当今数字时代,实现官网搜索引擎对于提升用户体验和推动整体性能至关重要。搜索引擎可以帮…...

OpenCV3-Python(7)模板匹配和霍夫检测
模板匹配 膜版匹配不能匹配尺度变换和视角变换的图像 图片中查找和模板相似度最高的图像 计算相似程度最高的位置 res cv.matchTemplate(img , template, method) 该方法返回一个类似灰度图的东西,如果用的相关匹配,那么亮的地方就是可能匹配上的地方 …...

[C++11]花括号{}、initializer_list、auto、decltype
文章目录 1.花括号{ }的扩展2.initializer_list3.auto4.decltype5.容器的增加5.1array[useless]5.2forward_list[useless]5.3unordered_map/unordered_set5.4统一增加 6.知乎文章 1.花括号{ }的扩展 int main() {//C98花括号{ }支持 1.数组 2.结构体struct Point{int _x;int _…...

在Android平板上使用code-server公网远程Ubuntu服务器编程
文章目录 1.ubuntu本地安装code-server2. 安装cpolar内网穿透3. 创建隧道映射本地端口4. 安卓平板测试访问5.固定域名公网地址6.结语 1.ubuntu本地安装code-server 准备一台虚拟机,Ubuntu或者centos都可以,这里以VMwhere ubuntu系统为例 下载code server服务,浏览器…...
宝塔上安装mysql版本比较和区别
在宝塔上安装MySQL时,几个主要版本之间的区别主要在于性能、功能和安全性。 MySQL Community Server(社区版本):这是MySQL的开源免费版本,由社区支持,但不提供官方技术支持。这个版本对一般用户来说可能有…...

uniapp微信小程序自定义封装分段器。
uniapp微信小程序自定义封装分段器。 话不多说先上效果 这里我用的是cil框架 vue3 下面贴代码 组价代码: <template><view class"page"><viewv-for"(item, index) in navList":key"index"click"changeNav(ind…...

文心一言 VS 讯飞星火 VS chatgpt (111)-- 算法导论10.2 2题
二、用go语言,用一个单链表 L实现一个栈。要求操作 PUSH和 POP 的运行时间仍为 O(1)。 文心一言: 在 Go 语言中,我们可以用结构体来实现一个单链表,然后再用栈的相关操作。 以下是一个可能的实现方式: package mai…...

小程序中使用echarts的相关配置以及折线图案例(简单易懂)
第一步:引入echarts文件--此文件需要下载: 下载地址:点击此处进行下载echarts文件 点击Download ZIP下载压缩包,注意:e-canvas是我从完整的文件中剥离出来的有用的,不会影响项目。 第二步:把整…...
前端面试回答不好的问题总结
vue生命周期: beforeCreated、created、beforeMount、mount、beforeUptade、uptade、beforeDestroy、destroyed、 Activated、Deactivated 闭包: ECMAScript中,闭包指的是: 从理论角度:所有的函数。因为它们都在创…...
漏洞预警|CVE-2023-38545 Curl 和 libcurl 堆缓冲区溢出漏洞
项目介绍 libcurl是一个跨平台的网络协议库,支持http、https、ftp等多种协议。 项目地址 https://github.com/curl/curl/releases 影响版本 7.69.0-8.3.0 漏洞分析 漏洞成因在于使用SOCKS5代理过程中造成的溢出。当Curl程序使用 SOCKS5代理时,设置…...

【Java 进阶篇】HTML 语义化标签详解
HTML(HyperText Markup Language)是构建Web页面的标准语言。在HTML中,标签(tag)是用于定义页面结构和内容的关键元素。在构建网页时,了解如何正确使用HTML标签是非常重要的,因为它们不仅影响页面…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...