Java多线程导入Excel示例

news2024/9/24 3:23:06

在导入Excel的时候,如果文件比较大,行数很多,一行行读往往速度比较慢,为了加快导入速度,我们可以采用多线程的方式
话不多说直接上代码
首先是Controller

import com.sakura.base.service.ExcelService;
import com.sakura.common.api.ApiResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/excel")
public class ExcelController {

    @Autowired
    private ExcelService excelService;

    @PostMapping("/import")
    public ApiResult<Boolean> importExcel(@ModelAttribute MultipartFile file) throws Exception {
        boolean flag = excelService.importExcel(file);
        return ApiResult.result(flag);
    }
}

然后Service

import org.springframework.web.multipart.MultipartFile;

public interface ExcelService {

    boolean importExcel(MultipartFile file) throws Exception;

}

ServiceImpl

import com.sakura.base.entity.User;
import com.sakura.base.mapper.UserMapper;
import com.sakura.base.service.ExcelService;
import lombok.extern.java.Log;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
@Log
public class ExcelServiceImpl implements ExcelService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean importExcel(MultipartFile file) throws Exception {
        // 文件为空这些校验大家自己加,这里只是做一个示例

        // 每次处理的数据量,大家可以自己调整,比如每次处理1000条
        int batchSize = 5;
        // 最大线程数,大家可以自己调整,根据自己服务器性能来调整
        int maxThreads = 3;

        // 创建一个线程池并设置最大线程数
        ExecutorService executorService = Executors.newFixedThreadPool(maxThreads);
        Workbook workbook = null;
        try {
            workbook = new XSSFWorkbook(file.getInputStream());

            // 获取第一页
            Sheet sheet = workbook.getSheetAt(0);
            // 获取总行数
            int rowCount = sheet.getLastRowNum();

            // 第0行一般为表头,从第一行开始
            int startRow = 1;
            // 结束行,Math.min用来比较两个数的大小,取最小值
            int endRow = Math.min(batchSize, rowCount);

            while (startRow <= rowCount) {
                // 提交任务到线程池
                executorService.execute(new ExcelRowProcessorTask(sheet, startRow, endRow));

                // 下一批数据的起始行
                startRow = endRow + 1;
                // 下一批数据的结束行
                endRow = Math.min(startRow + batchSize - 1, rowCount);
            }

            // 关闭线程池
            executorService.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return true;
    }

    private class ExcelRowProcessorTask implements Runnable {
        private final Sheet sheet;
        private final int startRow;
        private final int endRow;

        public ExcelRowProcessorTask(Sheet sheet, int startRow, int endRow) {
            this.sheet = sheet;
            this.startRow = startRow;
            this.endRow = endRow;
        }

        @Override
        public void run() {

            // _________________________________________
            // 测试用,模拟处理数据的耗时,实际应用删除
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // _________________________________________

            for (int i = startRow; i <= endRow; i++) {
                Row row = sheet.getRow(i);
                if (row != null) {
                    Cell nameCell = row.getCell(0); // 第一列
                    Cell phoneCell = row.getCell(1); // 第二列

                    nameCell.setCellType(CellType.STRING);
                    String name = nameCell.getStringCellValue();

                    phoneCell.setCellType(CellType.STRING);
                    String phoneNumber = phoneCell.getStringCellValue();

                    User user = new User();
                    user.setName(name);
                    user.setPhoneNumber(phoneNumber);

                    userMapper.insert(user);
                }
            }
        }
    }
}

实体类User就不贴了没啥好说的

还有就是poi的jar包

		<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.15</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.15</version>
        </dependency>

用postman验证上面的代码

在这里插入图片描述

可以看下数据库的数据,因为我限制了每次处理的数据为5条,同时最多有3个线程,所以可以看到同一时间段导进去的数据为15条

在这里插入图片描述

上面这个还有一个问题就是主线程不会等数据导入完就会返回,如果你需要主线程等待数据导入完可以加上下面这行代码

executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); // 等待所有任务执行完毕 Long.MAX_VALUE为超时时间,可以自由设置

就放在关闭线程池后面就可以了

在这里插入图片描述

有想看下怎么用多线程导出Excel的移步 Java多线程导出Excel示例

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

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

相关文章

URI is not registered (Settings | Languages Frameworks | Schemas and DTDs)

在我们实际编码&#xff0c;配置xml文件时&#xff0c;会出现如下的问题 因此应该从File->Settings-> 这样在xml中就显示正常了

SpringMVC--03--前端传数组给后台

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 案例1乘客个人信息方法1&#xff1a;表单提交&#xff0c;以字段数组接收方法2&#xff1a;表单提交&#xff0c;以BeanListModel接收方法3&#xff1a;将Json对象序…

S2---FPGA-A7板级原理图硬件实战

视频链接 FPGA-A7板级系统硬件实战01_哔哩哔哩_bilibili FPGA-A7板级原理图硬件实战 基于XC7A100TFGG484的FPGA硬件设计流程图 A7核心板&#xff0c;是基于XILINX公司的ARTIX-7系列100T的XC7A100T,2FGG484I这款芯片开发的高性能核心板&#xff0c;具有高速&#xff0c;高带宽&a…

B084-SpringCloud-Zuul Config

目录 zuul系统架构和zuul的作用zuul网关实现配置映射路径过滤器 Config概述云端管理本地配置 zuul zuul是分布式和集群后前端统一访问入口 系统架构和zuul的作用 zuul把自己注册进eureka&#xff0c;然后可通过前端传来的服务名发现和访问对应的服务集群 为了预防zuul单点故…

Raid5阵列数据恢复+Openmediavault配置内网与外网远程访问+服务器到服务器的大量文件转移备份

一、适用场景&#xff1a; 1、OpenMediaVault&#xff0c;是一个开源的&#xff08;免费&#xff09;基于Debian Linux的下一代网络附加存储(NAS)解决方案。 2、易于使用的 WEB 管理界面&#xff1a;OpenMediaVault 的用户界面设计直观&#xff0c;即使是没有 Linux 经验的用户…

FPGA-AXI4接口协议概述

假设我们要传一帧1080P的图片到显示屏显示&#xff0c;那么需要多大的储存空间呢&#xff1f; 一帧1080P的RGB565图像数据需要1920*1080*1633.1776Mb 存储空间 下图是ZYNQ-7000系列中Block RAM的大小&#xff1a; 可以看到最大存储空间的BRAM都不能存储一帧图片&#xff0c;那…

#QT(智能家居界面-布局)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a; 水平布局&#xff0c;垂直布局&#xff0c;栅格布局&#xff08;弹簧&#xff09; 界面自动调整 3.记录 注意弹簧不是拖拽拉长&#xff0c;而是使用栅格布局 运行发现窗口放大缩小可以自动调整 如果想要重新布局&#xff0c;需…

【短时交通流量预测】基于双层BP神经网络

课题名称&#xff1a;基于双层BP神经网络的短时交通流量预测 版本时间&#xff1a;2023-04-27 代码获取方式&#xff1a;QQ&#xff1a;491052175 或者 私聊博主获取 模型简介&#xff1a; 城市交通路网中交通路段上某时刻的交通流量与本路段前几个时段的交通流量有关&…

为什么各品牌主食冻干差价那么大?真正性价比高的主食冻干分享

随着科学养猫知识的普及&#xff0c;主食冻干喂养逐渐受到了许多铲屎官的青睐。然而&#xff0c;也有不少的铲屎官看到主食冻干的价格望而却步。实际上&#xff0c;像我这样的资深铲屎官早已开始主食冻干喂养。虽然主食冻干的价格相对于烘焙粮和膨化粮要高一些&#xff0c;但它…

es6 相关面试题

1 var, let ,const 区别&#xff1f; 2 手写将对象进行合并 手写合并对象 3 普通函数和箭头函数区别&#xff1f; 4 find 和 filter的区别&#xff1f; 5 some和every区别&#xff1f;

OCR 文字识别在未来会有哪些发展趋势?

随着技术的不断进步&#xff0c;OCR&#xff08;光学字符识别&#xff09;文字识别技术也在不断发展。未来&#xff0c;OCR 文字识别技术将会呈现以下几个发展趋势&#xff1a; 一、更高的识别准确率 OCR 技术的核心是识别准确率。随着深度学习等人工智能技术的发展&#xff0c…

测温线夹装置

测温线夹是一种用于测量温度的装置&#xff0c;通常用于电力系统中监测电气设备的温度。它可以安装在电气设备的导线上&#xff0c;通过感应导线的温度来测量电气设备的运行状态。测温线夹通常由金属材料制成&#xff0c;具有耐高温、耐腐蚀等特点&#xff0c;适用于各种恶劣的…

一文读懂Persistence One- 如何将Restaking带入Cosmos

Persistence One正在将Restaking引入Cosmos。用户将能够通过pSTAKE、Stride、Quicksilver和Milkyway将Liquid Staked Tokens&#xff08;如ATOM、TIA、DYDX等&#xff09;存入Persistence One&#xff0c;对其进行Restaking&#xff0c;从而安全地连接更多区块链&#xff0c;首…

苹果电脑专业的Mac垃圾清理工具CleanMyMac X4.14.7

CleanMyMac X是一款专业的Mac清理工具&#xff0c;它具有强大的功能和易用的界面&#xff0c;可以帮助用户快速清理Mac上的无用文件和垃圾&#xff0c;优化系统性能&#xff0c;提升电脑运行速度。 该软件的核心功能包括智能扫描与清理、应用程序管理、隐私保护和系统维护等。…

Python的http模块requests

模块简介&#xff1a; requests 库是一个 python中比较有名的 http请求的库&#xff0c;能处理 get,post,put,delete 等 restful请求&#xff0c;能设置 header&#xff0c;cookie,session 等操作&#xff0c;也是作为爬虫的基础库&#xff0c;它目前还不能异步请求,如果要支持…

Spring循环依赖:原因与解决方法

在Spring框架中&#xff0c;处理循环依赖一直备受关注。这是因为Spring团队在源代码中为了解决这个问题做了大量的处理和优化。同时&#xff0c;循环依赖也是Spring高级面试中的必考问题&#xff0c;对其深入了解可以成为面试中的制胜法宝。本文将详细介绍Spring循环依赖的产生…

【Datawhale组队学习:Sora原理与技术实战】Attention和LLM

Attention Attention 注意力&#xff0c;从两个不同的主体开始。 论文&#xff1a;https://arxiv.org/pdf/1703.03906.pdf seq2seq代码仓&#xff1a;https://github.com/google/seq2seq 计算方法&#xff1a; 加性Attention&#xff0c;如&#xff08;Bahdanau attention&…

备战蓝桥杯---图论应用1

目录 1.增加虚点建图&#xff1a; 2.抽象图的迪杰斯特拉&#xff1a; 3.用bitset优化弗洛伊德&#xff1a; 4.有向图的Prim/kruskal&#xff1a; 1.增加虚点建图&#xff1a; 我们当然可以每一层与上一层的点再连上一条边&#xff0c;但这样子边太多了超内存&#xff0c;我们…

【学习心得】网站运行时间轴(爬虫逆向)

一、网站运行时间轴 掌握网站运行时间轴&#xff0c;有助于我们对“请求参数加密”和“响应数据加密”这两种反爬手段的深入理解。 二、从网站运行的时间轴角度来理解两种反爬手段 1、加载HTML&#xff1a; 这是浏览器访问网站时的第一步&#xff0c;服务器会返回基础…

6.Java---二维数组

打印二维数组的每个元素 上图所示,我们打印的时候将行列的数字写死,但是实际上如果这个数组有很多元素我们还要一个个数数嘛?这不是很占用我们的时间啦!因此引出下文. 代码精进 二维数组的每个元素是一个一维数组 打印二维数组的法2 打印出的格式如下: 不规则的二维数组…