EasyExcel百万数据导入导出

文章目录

  • 百万数据准备
  • EasyExcel导出
    • EasyExcel不支持并发写
    • 导出功能的代码片段
  • EasyExcel导入

https://gitee.com/antirust/idooy-stable/tree/master/idooy-EasyExcel

开发中,导入导出功能对于后台管理这样的系统来说太常用了,除了实现该功能外导入导出的性能也需要开发人员进行充分的考虑。一般情况下,针对导入导出功能的设计会面临如下几个问题:

  1. 如果同步导数据,系统的承载的数据量会不会导致接口超时。
  2. 如果把所有数据一次性装载到内存,很容易引起OOM。
  3. 数据量太大sql语句必定很慢。
  4. 如果走异步,如何通知用户导出结果?
  5. 如果excel文件太大,目标用户打不开怎么办?

个别系统导入导出业务复杂,出现问题的地方就不局限于上面的这几个点,开发中如果是优化的话,那也无法抛开复杂的业务场景而单纯的去讨论导入导出的功能。曾经就亲身经历过业务员导入7W条数据跑好几个小时,同步导出10W条数据接口超时。如果没有业务逻辑从中作梗;单纯的导入和导出10W条数据还是很轻松的。
总之,导出导入功能如果追求效率,就需要往多线程上靠;必要的话,还需要进行异步操作。
本小节基于EasyExcel使用多线程进行高效的导入导出操作

百万数据准备

300W的数据大概97M大小
存储过程

create procedure insert_emp(IN num int)
begindeclare i int default 0;set autocommit = 0;repeatinsert into employee(last_name, age, sex, salary, job_id)values (concat('emp', lpad(i, 8, '0')), floor(rand() * 100), if(rand() > 0.5, '男', '女'),round(rand() * 10000), floor(rand() * 10));set i = i + 1;until i = num end repeat;commit;
end;

表结构创建语句

create table if not exists employee
(employee_id    int auto_increment primary key,last_name      varchar(100) null,age            int          null,sex            varchar(1)   null,salary         decimal      null,job_id         int          null
);

插入300W数据

call insert_emp(3000000);

EasyExcel导出

导出分两步:

  • select查询数据(多线程分页查询)
  • 数据write写入文件中(因为EasyExcel不支持并发写,即不管是多线程写入单个sheet,还是多线程写入多个sheet都是不允许的)

故EasyExcel高效率导出,就是要合理的使用多线程进行分页数据的查询,(当然还要考虑SQL有没有优化的空间,这里不进行讨论)

EasyExcel不支持并发写

EasyExcel版本3.3.3,并发写的时候程序异常;查看官方文档,文档明确指出‘不支持并发写’
在这里插入图片描述
具体解决办法参看GitHub-issues#3020

导出功能的代码片段

    Long count = baseMapper.selectCount(queryWrapper);Long sheetNum = count % pageSize == 0 ? count / pageSize:count / pageSize + 1;// 多线程去读// 1.初始化map容量 防止扩容带来的效率损耗Map<Integer, Page<T>> pageMap = new ConcurrentHashMap<>(Math.toIntExact(3));CountDownLatch countDownLatch = new CountDownLatch(Math.toIntExact(3));// 注意 easyexcel 暂时不支持多线程并发写入!!! 详情请看github上issuesfor (int i = 0 ;i< sheetNum;i++){int finali = i;threadPoolTaskExecutor.submit(()->{Page<T> page = new Page<>();page.setCurrent(finali + 1);page.setSize(pageSize);// 获取数据存放到map中Page<T> selectPage = baseMapper.selectPage(page,queryWrapper);pageMap.put(finali,selectPage);// 消耗掉一个countDownLatch.countDown();});}try {countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}// 写入try (ExcelWriter excelWriter = EasyExcel.write(out, pojoClass).build()) {pageMap.forEach((k,v)->{log.info("正在写入{}条数据",pageSize);WriteSheet writeSheet = EasyExcel.writerSheet(k, "第"+(k+1)+"批数据").build();excelWriter.write(v.getRecords(), writeSheet);pageMap.remove(k);});excelWriter.finish();}

EasyExcel导入

EasyExcel导入思路如下:

  • 解析一行插入一行(速度太慢,不可取)
  • 逐行解析到达指定行数(EasyExcel提供PageReadListener类);数据库批量插入
EasyExcel.read(resource.getInputStream(), Employee.class, new PageReadListener<Employee>((empList) -> {// 方式三:多线程批量插入,每次批量插入10W数据,100W数据一共用时12sthreadPool.execute(() -> 		employeeMapper.insertBatchSomeColumn(empList));log.info("成功插入一次{}量的数据", batchSize);
}, batchSize)).sheet().doRead();
  • 如果是多个sheet页
    • 每个线程处理一个sheet;
      • 解析指定的行数以后单线程批量插入。
      • 解析指定的行数以后多线程批量插入。

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

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

相关文章

Python爬虫-爬取豆瓣Top250电影信息

&#x1f388; 博主&#xff1a;一只程序猿子 &#x1f388; 博客主页&#xff1a;一只程序猿子 博客主页 &#x1f388; 个人介绍&#xff1a;爱好(bushi)编程&#xff01; &#x1f388; 创作不易&#xff1a;喜欢的话麻烦您点个&#x1f44d;和⭐&#xff01; &#x1f388;…

QT qss文件设置样式

方式一 &#xff08;单个&#xff09; 方式二 &#xff08;全局&#xff09; 所有按钮都会采用这个样式。 方式三 &#xff08;qss文件&#xff09; 创建资源文件 创建qss文件&#xff08;Button.qss&#xff09; 引用qss文件 QApplication a(argc, argv);QString qss;QFile…

Kettle Local引擎使用记录(一)(基于Kettle web版数据集成开源工具data-integration源码)

Kettle Web &#x1f4da;第一章 前言&#x1f4da;第二章 demo源码&#x1f4d7;pom.xml引入Kettle引擎核心文件&#x1f4d7;java源码&#x1f4d5; controller&#x1f4d5; service&#x1f4d5; 其它&#x1f4d5; maven settings.xml &#x1f4d7;测试&#x1f4d5; 测试…

【STM32】STM32学习笔记-USART串口数据包(28)

00. 目录 文章目录 00. 目录01. 串口简介02. HEX数据包03. 文本数据包04. HEX数据包接收05. 文本数据包接收06. 预留07. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式&#xff0c;因为它简单便捷&#xff0c;因此大部分电子设备都支持…

Python 使用input函数从键盘输入数据

在Python中&#xff0c;input()函数可以从键盘获取用户的输入数据。当我们使用input()函数时&#xff0c;会暂停程序的执行&#xff0c;等待用户输入数据&#xff0c;并将用户输入的数据作为字符串返回。 如&#xff1a; name input("请输入你的姓名&#xff1a;"…

Python私有变量的定义与访问

class Student():def __init__(self, name, age):self.name nameself.age ageself.__score 0def marking(self, score):if score < 0:return 分数不能为0self.__score scoreprint(self.name 同学本次得分是: str(self.__score)) def __talk(self): # 私有的类可通过在…

RocketMQ5-03RocketMQ-Dashboard和Java客户端访问示例

接上篇02快速部署RocketMQ5.x(手动和容器部署) 已经完成 RocketMQ5.0 环境的部署&#xff0c;就需要对这个环境进行测试&#xff0c;查看集群、写入消息、读取消息等 本篇教你如何使用和查看部署的服务&#xff1a; Docker部署 Dashboard 获取镜像并下载部署服务 客户端连接 …

哈希-力扣01两数之和

题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意顺…

spring boot 2升级为spring boot 3中数据库连接池druid的问题

目录 ConfigurationClassPostProcessor ConfigurationClassBeanDefinitionReader MybatisPlusAutoConfiguration ConditionEvaluator OnBeanCondition 总结 近期给了一个任务&#xff0c;要求是对现有的 spring boot 2.x 项目进行升级&#xff0c;由于 spring boot 2.x 版…

Linux Capabilities 进阶实战

目录 1. 快速回顾 2. 为可执行文件分配 capabilities 3. 构建半特权环境 4. 容器与 capabilities Linux Capabilities 基础概念与基本使用 上一篇学习了LinuxCapabilities的基础知识和基本使用&#xff0c;因为后面需要学习Docker的逃逸&#xff0c;理解Linux Capabilitie…

忆阻器芯片STELLAR权重更新算法(清华大学吴华强课题组)

参考文献&#xff08;清华大学吴华强课题组&#xff09; Zhang, Wenbin, et al. “Edge learning using a fully integrated neuro-inspired memristor chip.” Science 381.6663 (2023): 1205-1211. STELLAR更新算法原理 在权值更新阶段&#xff0c;只需根据输入、输出和误差…

在python里面探索web框架

一、常识性知识 python Web框架三巨头&#xff1a;Flask&#xff08;简单易学&#xff09;、Django(复杂庞大)、FastAPI 1. Django&#xff1a;Django是一个高级的Web框架&#xff0c;它提供了强大的功能和工具&#xff0c;用于快速开发复杂的Web应用程序。 2. Flask&#xff…

【Java集合篇】ConcurrentHashMap是如何保证线程安全的

ConcurrentHashMap是如何保证线程安全的 ✔️典型解析✔️ 拓展知识仓✔️ 什么是CAS&#xff08;Compare And Swap&#xff09;✔️CAS和互斥量有什么区别✔️如何使用CAS和互斥量 ✔️CAS和Synchronized的区别✔️ConcurrentHashMap的优缺点✔️能用ConcurrentHashMap实现队列…

python对常见的激活函数绘图操作(详细代码讲解)

写论文的时候需要做一些激活函数的图像&#xff0c;为此将常见的激活函数进行整理汇总了一下&#xff0c;方便后续的复习 激活函数的作用是为让模型处理非线性问题&#xff0c;故次激活函数都是非线性的 生活中&#xff0c;非线性问题占大多数&#xff0c;而模型的训练通常都是…

哈希表-散列表数据结构

1、什么是哈希表&#xff1f; 哈希表也叫散列表&#xff0c;哈希表是根据关键码值(key value)来直接访问的一种数据结构&#xff0c;也就是将关键码值(key value)通过一种映射关系映射到表中的一个位置来加快查找的速度&#xff0c;这种映射关系称之为哈希函数或者散列函数&…

Rollup-plugin-bundle-analyzer VS Rollup-plugin-visualizer

分析和可视化Rollup打包后的文件的插件 Rollup-plugin-bundle-analyzerRollup-plugin-visualizer Rollup-plugin-bundle-analyzer和Rollup-plugin-visualizer都是用于分析和可视化Rollup打包后的文件的插件&#xff0c;但它们在功能和使用方式上存在一些差异。 Rollup-plugi…

PostGIS教程学习十九:基于索引的聚簇

PostGIS教程学习十九&#xff1a;基于索引的聚簇 数据库只能以从磁盘获取信息的速度检索信息。小型数据库将完全位于于RAM缓存&#xff08;内存&#xff09;&#xff0c;并摆脱物理磁盘访问速度慢的限制。但是对于大型数据库&#xff0c;对物理磁盘的访问将限制数据库的信息检…

FFmpeg获取音视频流信息

文章目录 前言一、需求二、源码三、运行结果 前言 本文记录用 FFmpeg 获取视频流音频流的信息&#xff08;编码格式、分辨率、帧率、播放时长…&#xff09;&#xff0c;所用的工程基于上个博客编译成功的工程&#xff1a;使用FFmpeg4.3.1的SDK官方开发包编译ffmpeg.c 一、需求…

透明OLED拼接屏:重塑大屏显示的新篇章

随着科技的快速发展&#xff0c;大屏显示技术已经逐渐渗透到我们生活的方方面面。作为显示技术领域的一大革新&#xff0c;透明OLED拼接屏以其独特的透明显示特性&#xff0c;正逐渐成为大屏显示市场的新宠。尼伽小编将深入探讨透明OLED拼接屏的技术特点、应用场景以及市场前景…

中国葡萄酒消费者的口味偏好

有一段时间&#xff0c;“中国口味”的问题是全世界葡萄酒销售者的热门话题&#xff0c;因为他们积极探索每一个线索&#xff0c;以发现让他们在市场上领先的秘密。为此进行了大量研究&#xff0c;多年前葡萄酒销售商或多或少形成了一个共识&#xff1a;尽管中国人的口味差异很…