基于java线程池和EasyExcel实现数据异步导入

基于java线程池和EasyExcel实现数据异步导入

2.代码实现

2.1 controller层

    @PostMapping("import")public void importExcel(MultipartFile file) throws IOException {importService.importExcelAsync(file);}

2.2 service层

@Resource
private SalariesListener salariesListener;private ExecutorService executorService = Executors.newFixedThreadPool(20);public void importExcelAsync(MultipartFile file) {// 开20个线程分别处理20个sheetList<Callable<Object>> tasks = new ArrayList<>();for (int i = 0; i < 20; i++) {int num = i;tasks.add(() -> {EasyExcel.read(file.getInputStream(), Salaries.class, salariesListener).sheet(num).doRead();return null;});}try {//等待所有任务完成executorService.invokeAll(tasks);} catch (InterruptedException e) {throw new RuntimeException(e);}}

2.3实体

@Data
@TableName("salaries")
public class Salaries {private Integer empNo;private Integer salary;private Date fromDate;private Date toDate;
}

2.4easyExcel 监听

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.domain.Salaries;
import com.woniu.mapper.SalariesMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;@Component
public class SalariesListener extends ServiceImpl<SalariesMapper, Salaries> implements ReadListener<Salaries>, IService<Salaries> {private static final Log logger = LogFactory.getLog(SalariesListener.class);//创建一个线程池,用于异步保存数据private ExecutorService executorService = Executors.newFixedThreadPool(20);//创建一个线程安全的list,用于存储读取到的数据,使用ThreadLocal保证线程安全private ThreadLocal<ArrayList<Salaries>> salariesList = ThreadLocal.withInitial(ArrayList::new);//用于统计是第几次插入private static AtomicInteger count = new AtomicInteger(1);//设定需要异步批量插入的条数private static final int batchSize = 10000;@Resourceprivate SalariesListener salariesListener;@Override@Transactional(rollbackFor = Exception.class)public void invoke(Salaries data, AnalysisContext context) {//读取excel每一行的数据,添加到list中salariesList.get().add(data);//如果list的数据大于设定需要异步批量插入的条数,则执行异步插入if (salariesList.get().size() >= batchSize) {asyncSaveData();}}public void saveData() {if (!salariesList.get().isEmpty()) {saveBatch(salariesList.get(), salariesList.get().size());logger.info("第" + count.getAndAdd(1) + "次插入" + salariesList.get().size() + "条数据");salariesList.get().clear();}}public void asyncSaveData() {if (!salariesList.get().isEmpty()) {ArrayList<Salaries> salaries = (ArrayList<Salaries>) salariesList.get().clone();executorService.execute(new SaveTask(salaries, salariesListener));salariesList.get().clear();}}@Override@Transactional(rollbackFor = Exception.class)public void doAfterAllAnalysed(AnalysisContext context) {logger.info("一个Sheet全部处理完");//考虑每个sheet批量插入数据的条数少于异步插入的条数asyncSaveData();}//创建一个线程类,用于异步保存数据static class SaveTask implements Runnable {private List<Salaries> salariesList;private SalariesListener salariesListener;public SaveTask(List<Salaries> salariesList, SalariesListener salariesListener) {this.salariesList = salariesList;this.salariesListener = salariesListener;}@Overridepublic void run() {salariesListener.saveBatch(salariesList);//打印第几次插入,每次插入的数据logger.info("第" + count.getAndAdd(1) + "次插入" + salariesList.size() + "条数据");}}
}

2.5 建表语句

CREATE TABLE `salaries` (`emp_no` int(11) DEFAULT NULL COMMENT '员工号',`salary` int(11) DEFAULT NULL,`from_date` datetime DEFAULT NULL,`to_date` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
spring:servlet:multipart:max-request-size: 30MBmax-file-size: 1024MBdatasource:username: rootpassword: rooturl: jdbc:mysql://127.0.0.1:3306/llp?rewriteBatchedStatements=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghaimain:allow-circular-references: true

3.测试验证

可以看到导入95万多条数据,耗时差不多在一份多钟

  • 导入开始时间

image-20250123102709029

  • 导入结束时间

image-20250123102727318

  • 入库数据

image-20250123102825151

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

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

相关文章

linux asio网络编程理论及实现

最近在B站看了恋恋风辰大佬的asio网络编程&#xff0c;质量非常高。在本章中将对ASIO异步网络编程的整体及一些实现细节进行完整的梳理&#xff0c;用于复习与分享。大佬的博客&#xff1a;恋恋风辰官方博客 Preactor/Reactor模式 在网络编程中&#xff0c;通常根据事件处理的触…

Python爬虫学习第三弹 —— Xpath 页面解析 实现无广百·度

早上好啊&#xff0c;大佬们。上回使用 Beautiful Soup 进行页面解析的内容是不是已经理解得十分透彻了~ 这回我们再来尝试使用另外一种页面解析&#xff0c;来重构上一期里写的那些代码。 讲完Xpath之后&#xff0c;小白兔会带大家解决上期里百度搜索的代码编写&#xff0c;保…

docker安装MySQL8:docker离线安装MySQL、docker在线安装MySQL、MySQL镜像下载、MySQL配置、MySQL命令

一、镜像下载 1、在线下载 在一台能连外网的linux上执行docker镜像拉取命令 docker pull mysql:8.0.41 2、离线包下载 两种方式&#xff1a; 方式一&#xff1a; -&#xff09;在一台能连外网的linux上安装docker执行第一步的命令下载镜像 -&#xff09;导出 # 导出镜…

特权模式docker逃逸

目录 1.环境 2.上线哥斯拉 3.特权模式逃逸 1.判断是否为docker环境 2.判断是否为特权模式 3.挂载宿主机磁盘到docker 4.计划任务反弹shell 1.环境 ubuntu部署一个存在CVE-2017-12615的docker: (ip:192.168.117.147) kali(ip:192.168.117.128) 哥斯拉 2.上线哥斯拉…

Direct2D 极速教程(1) —— 画图形

极速导航 Direct2D 简介创建新项目&#xff1a;001-DrawGraphics弄一个白窗口在窗口上画图 Direct2D 简介 大家在学 WINAPI 的时候的时候有没有想过&#xff0c;怎么在一副窗口上画图呢&#xff1f;大家知道 Windows 系统是 GUI 图形用户界面 系统&#xff0c;以 Graphics 图形…

(长期更新)《零基础入门 ArcGIS(ArcScene) 》实验七----城市三维建模与分析(超超超详细!!!)

城市三维建模与分析 三维城市模型已经成为一种非常普遍的地理空间数据资源,成为城市的必需品,对城市能化管理至关重要。语义信息丰富的三维城市模型可以有效实现不同领域数据与IS相信息的高层次集成及互操作,从而在城市规划、环境模拟、应急响应和辅助决策等众多领域公挥作用、…

ArcGIS10.2 许可License点击始终启动无响应的解决办法及正常启动的前提

1、问题描述 在ArcGIS License Administrator中&#xff0c;手动点击“启动”无响应&#xff1b;且在计算机管理-服务中&#xff0c;无ArcGIS License 或者License的启动、停止、禁止等均为灰色&#xff0c;无法操作。 2、解决方法 ①通过cmd对service.txt进行手动服务的启动…

目标跟踪之sort算法(3)

这里写目录标题 1 流程1 预处理2 跟踪 2 代码 参考&#xff1a;sort代码 https://github.com/abewley/sort 1 流程 1 预处理 1.1 获取离线检测数据。1.2 实例化跟踪器。2 跟踪 2.1 轨迹处理。根据上一帧的轨迹预测当前帧的轨迹&#xff0c;剔除到当前轨迹中为空的轨迹得到当前…

物业巡更系统在现代社区管理中的优势与应用探讨

内容概要 在现代社区管理中&#xff0c;物业巡更系统正逐渐成为一种不可或缺的工具。结合先进的智能技术&#xff0c;这些系统能够有效地提升社区管理的各个方面&#xff0c;尤其是在巡检效率和信息透明度方面。通过实时记录巡检数据&#xff0c;物业管理人员能够确保工作人员…

深入探讨防抖函数中的 this 上下文

深入剖析防抖函数中的 this 上下文 最近我在研究防抖函数实现的时候&#xff0c;发现一个耗费脑子的问题&#xff0c;出现了令我困惑的问题。接下来&#xff0c;我将通过代码示例&#xff0c;深入探究这些现象背后的原理。 示例代码 function debounce(fn, delay) {let time…

进程通讯——类型和发展

进程常用交互方法如上

健康AI应用的逆袭:如何用“死亡时钟”撬动用户增长和媒体关注,实现应用榜快速排名第六

Death Clock&#xff1a;一款AI驱动的长寿应用 过去六个月里&#xff0c;我一直在为一款名为 Death Clock 的AI驱动长寿应用提供建议。健康类应用的增长向来十分困难&#xff0c;因为它们通常是单人使用的工具&#xff0c;且主要吸引年长的用户群体。然而&#xff0c;与创始人…

区块链在能源行业的应用场景

区块链技术在能源行业的应用正在逐步扩展&#xff0c;并且展现出巨大的潜力。它不仅能够促进能源交易的透明度和效率&#xff0c;还能为能源生产、分配、消费等多个环节提供创新解决方案。以下是对区块链在能源行业应用的一些深入探讨&#xff1a; 1. 能源交易 区块链可以实现…

论文阅读(十五):DNA甲基化水平分析的潜变量模型

1.论文链接&#xff1a;Latent Variable Models for Analyzing DNA Methylation 摘要&#xff1a; 脱氧核糖核酸&#xff08;DNA&#xff09;甲基化与细胞分化密切相关。例如&#xff0c;已经观察到肿瘤细胞中的DNA甲基化编码关于肿瘤的表型信息。因此&#xff0c;通过研究DNA…

基于PostgreSQL的自然语义解析电子病历编程实践与探索(上)

一、引言 1.1研究目标与内容 本研究旨在构建一个基于 PostgreSQL 的自然语义解析电子病历编程体系,实现从电子病历文本中提取结构化信息,并将其存储于 PostgreSQL 数据库中,以支持高效的查询和分析。具体研究内容包括: 电子病历的预处理与自然语言处理:对电子病历文本进…

第1章 量子暗网中的血色黎明

月球暗面的危机与阴谋 量子隧穿效应催生的幽蓝电弧&#xff0c;于环形山表面肆意跳跃&#xff0c;仿若无数奋力挣扎的机械蠕虫&#xff0c;将月球暗面的死寂打破&#xff0c;徒增几分诡异。艾丽伫立在被遗弃的“广寒宫”量子基站顶端&#xff0c;机械义眼之中&#xff0c;倒映着…

【落羽的落羽 数据结构篇】顺序表

文章目录 一、线性表二、顺序表1. 概念与分类2. 准备工作3. 静态顺序表4. 动态顺序表4.1 定义顺序表结构4.2 顺序表的初始化4.3 检查空间是否足够4.3 尾部插入数据4.4 头部插入数据4.5 尾部删除数据4.6 头部删除数据4.7 在指定位置插入数据4.8 在指定位置删除数据4.9 顺序表的销…

大模型GUI系列论文阅读 DAY4续:《Large Language Model Agent for Fake News Detection》

摘要 在当前的数字时代&#xff0c;在线平台上虚假信息的迅速传播对社会福祉、公众信任和民主进程构成了重大挑战&#xff0c;并影响着关键决策和公众舆论。为应对这些挑战&#xff0c;自动化假新闻检测机制的需求日益增长。 预训练的大型语言模型&#xff08;LLMs&#xff0…

基于物联网的智能环境监测系统(论文+源码)

1系统的功能及方案设计 本课题为基于物联网的智能环境监测系统的设计与实现&#xff0c;整个系统采用stm32f103单片机作为主控制器&#xff0c;通过DHT11传感器实现智能环境监测系统温度和湿度的检测&#xff0c;通过MQ传感器实现CO2浓度检测&#xff0c;通过光照传感器实现光照…

反向代理模块。。

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当于…