十分钟三个步骤给百万级数据Excel多人同时导出添加排队导出功能,避免干崩服务器

news2025/2/27 13:59:31

 业务场景

考虑到数据库数据日渐增多,导出会有全量数据的导出(甚至有的时候数据百万级),多人同时导出可以会对服务性能造成影响,导出涉及到mysql查询的io操作,还涉及文件输入、输出流的io操作,所以对服务器的性能会影响的比较大。因为需要控制频繁操作导出功能,优化用户体验。

 

解决方案

  • 创建队列

        维护一个FIFO(先进先出)的队列,用于存储需要进行导出操作的用户请求。设置队列大小:根据服务器性能和资源的情况,确定队列的大小,以限制同时进行导出操作的请求数量,防止造成服务性能下降。

@Slf4j
@Component
public class ExportQueue {


    private final int MAX_CAPACITY = 10; // 队列最大容量
    private LinkedList<ExportUser> queue; // 用户队列

    public ExportQueue(LinkedList<ExportUser> queue) {
        this.queue = new LinkedList<>();
    }

    /**
     * 排队队列添加
     * @param sysUser
     */
    public synchronized LinkedList<ExportUser> add(ExportUser sysUser) {
        while (queue.size() >= MAX_CAPACITY) {
            try {
                log.info("当前排队人已满,请等待");
                wait();
            } catch (InterruptedException e) {
                e.getMessage();
            }
        }
        queue.add(sysUser);
        log.info("目前导出队列排队人数:" + queue.size());
        notifyAll();
        return queue;
    }


    /**
     * 获取排队队列下一个人
     * @return
     */
    public synchronized ExportUser getNextSysUser() {
        while (queue.isEmpty()) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        ExportUser sysUser = queue.remove();
        notifyAll(); //唤醒
        return sysUser;
    }
}

 

  • 使用easyExcel导出

         EasyExcel 是阿里巴巴开源的项目,具有高性能和稳定性,并且拥有丰富的文档和示例代码,方便开发人员使用和学习。具有百万级数据处理导出的优势。


@Slf4j
public abstract class AbstractExport<T, K> {


    public abstract void export(ExportUser sysUser) throws InterruptedException;

    /**
     * 导出
     *
     * @param response 输出流
     * @param pageSize 每页大小
     * @param t        导出条件
     * @param k        Excel内容实体类
     * @param fileName 文件名称
     */
    public void export(HttpServletResponse response, int pageSize, T t, Class<K> k, String fileName) throws Exception {
        ExcelWriter writer = null;
        try {
            writer = getExcelWriter(response, fileName);
            //查询导出总条数
            int total = this.countExport(t);
            //页数
            int loopCount = PageUtil.totalPage(total, pageSize);
            BeanUtil.setProperty(t, "pageSize", pageSize);
            for (int i = 0; i < loopCount; i++) {
                //开始页
                BeanUtil.setProperty(t, "pageNum", PageUtil.getStart(i + 1, pageSize));
                //获取Excel导出信息
                List<K> kList = this.getExportDetail(t);
                WriteSheet writeSheet = EasyExcel.writerSheet(fileName).head(k).build();
                writer.write(kList, writeSheet);
            }
        } catch (Exception e) {
            String msg = "导出" + fileName + "异常";
            log.error(msg, e);
            throw new Exception(msg + e);
        } finally {
            if (writer != null) {
                writer.finish();
            }
        }
    }

    public com.alibaba.excel.ExcelWriter getExcelWriter(HttpServletResponse response, String fileName) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileNameUtf = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileNameUtf + ".xlsx");
        return EasyExcel.write(response.getOutputStream()).build();
    }


    /**
     * (模版导出)
     *
     * @param t
     * @param fileName
     * @param response
     */
    public abstract void complexFillWithTable(T t, String fileName, HttpServletResponse response);

    /**
     * 查询导出总条数
     *
     * @param t
     * @return
     */
    public abstract int countExport(T t);

    /**
     * 查询导出数据
     *
     * @param t
     * @return
     */
    public abstract List<K> getExportDetail(T t);
}
@Service
@Slf4j
public class ExportImpl extends AbstractExport {

    @Autowired
    private ExportQueue exportQueue;


    @Override
    public void export(ExportUser sysUser) throws InterruptedException {

        //导出
        log.info("导出文件方法执行~~~~~~~~~");
//        export(response,pageSize,t,k,fileName);
        LinkedList<ExportUser> queue = exportQueue.add(sysUser);
        log.info("导出队列:" + queue);
        //休眠时间稍微设置大点,模拟导出处理时间
        Thread.sleep(20000);
        //导出成功后移除当前导出用户
        ExportUser nextSysUser = exportQueue.getNextSysUser();
        log.info("移除后获取下一个排队的用户: " + nextSysUser.getUserName());

    }


    @Override
    public void export(HttpServletResponse response, int pageSize, Object o, Class k, String fileName) throws Exception {
        super.export(response, pageSize, o, k, fileName);
    }

    @Override
    public ExcelWriter getExcelWriter(HttpServletResponse response, String fileName) throws IOException {
        return super.getExcelWriter(response, fileName);
    }

    @Override
    public void complexFillWithTable(Object o, String fileName, HttpServletResponse response) {

    }

    @Override
    public int countExport(Object o) {
        return 0;
    }

    @Override
    public List getExportDetail(Object o) {
        return null;
    }
}
  •  测试类


@Test
public void test(){
    new Thread(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    Thread thread1 = Thread.currentThread();
                    ExportUser sysUser =new ExportUser();
                    sysUser.setUserName(thread1.getName());

                    export.export(sysUser);
                }
            }).start();
        }
}

导出进度通知

        可以考虑在导出操作完成后,向用户发送通知,告知导出操作已完成,提供相应的下载链接。资源限制和优化:在导出操作涉及到数据库查询和文件IO操作时,可以针对性地进行优化,减少对服务器性能的影响。例如,使用合适的索引以提高数据库查询效率,使用缓冲区来提高文件IO操作效率等。

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

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

相关文章

算法day02_209.长度最小的子数组

推荐阅读 从零开始学数组&#xff1a;深入浅出&#xff0c;带你掌握核心要点 初探二分法 再探二分法 目录 推荐阅读209.长度最小的子数组题目思路解法暴力解法队列相加法&#xff08;滑动窗口&#xff09;对列相减法&#xff08;滑动窗口&#xff09; 系统的纪录一下刷算法的过…

特斯拉一面算法原题

来自太空的 X 帖子 埃隆马斯克&#xff08;Elon Musk&#xff09;旗下太空探索技术公司 SpaceX 于 2 月 26 号&#xff0c;从太空往社交平台 X&#xff08;前身为推特&#xff0c;已被马斯克全资收购并改名&#xff09;发布帖子。 这是 SpaceX 官号首次通过星链来发送 X 帖子&a…

Rocky Linux 运维工具yum

一、yum的简介 ​​yum​是用于在基于RPM包管理系统的包管理工具。用户可以通过 ​yum​来搜索、安装、更新和删除软件包&#xff0c;自动处理依赖关系&#xff0c;方便快捷地管理系统上的软件。 二、yum的参数说明 1、install 用于在系统的上安装一个或多个软件包 2、seach 用…

React中使用useActive

1.引入 import { useActivate } from "react-activation";2.React Activation 在React中使用react-activation,其实就是类似于Vue中的keep-alive&#xff0c;实现数据的缓存&#xff1b; 源码&#xff1a; import { ReactNode, ReactNodeArray, Context, Component…

密码学在 Web3 钱包中的应用:私钥是什么?bitget钱包为例

在非对称加密演算法中&#xff0c;私钥是一串随机生成的数字&#xff0c;通常以十六进制数表示&#xff08;也就是由0、1、2、3、4、5、6、7、8、9、a、b、c、d、e和f组成&#xff09;。私钥生成后&#xff0c;这串数字被作为一个单向数学函数中的输入值&#xff0c;计算产生的…

python web框架fastapi模板渲染--Jinja2使用技巧总结

文章目录 1.jinja2模板1.1、jinja2 的变量1.1.1 列表类型数据渲染1.1.2 字典类型数据渲染 2. jinja2 的过滤器3. jinja2 的控制结构3.1、分支控制3.2、循环控制 1.jinja2模板 要了解jinja2&#xff0c;那么需要先理解模板的概念。模板在Python的web开发中⼴泛使⽤&#xff0c;…

Python多线程编程:深入理解threading模块及代码实战【第99篇—Multiprocessing模块】

Python多线程编程&#xff1a;深入理解threading模块及代码实战 在Python编程中&#xff0c;多线程是一种常用的并发编程方式&#xff0c;它可以有效地提高程序的执行效率&#xff0c;特别是在处理I/O密集型任务时。Python提供了threading模块&#xff0c;使得多线程编程变得相…

springboot 注解属性转换字典

1.注解相关功能实现 定义属性注解 import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.vehicle.manager.core.serializer.DicSerializer;import java.lang.annotation.*;/*** a…

图神经网络实战——图论

图神经网络实战——图论 0. 前言1. 图属性1.1 有向图和无向图1.2 加权图与非加权图1.3 连通图非连通图1.4 其它图类型 2. 图概念2.1 基本对象2.2 图的度量指标2.2 邻接矩阵表示法 3. 图算法3.1 广度优先搜索3.2 深度优先搜索 小结系列链接 0. 前言 图论 (Graph theory) 是数学…

【深度学习:标记数据】为医生标记数据缓解疼痛

【深度学习&#xff1a;标记数据】为医生标记数据缓解疼痛 问题实验结果结论 我开始在物理学方面进行学术研究&#xff0c;但在第一年就退学了&#xff08;抱歉&#xff0c;休学了&#xff09;我的博士学位&#xff0c;并在定量金融领域做了很长一段时间。因此&#xff0c;在我…

从0到1实现五子棋游戏!!

Hello&#xff0c;好久不见宝子们&#xff0c;今天来给大家更一个五子棋的程序~ 我们今天要讲的内容如下&#xff1a; 文章目录 1.五子棋游戏介绍1.1 游戏玩法介绍&#xff1a; 2.准备工作2.1 具体操作流程 3.游戏程序主函数4.初始化棋盘4.1.定义宏变量4.2 初始化棋盘 5.打印…

git的使用 -- 代码托管平台阿里云

准备工作&#xff1a;git下载&#xff0c;环境配置git config --global user.name/user.email &#xff08;这个是注解不用加&#xff0c;这里是两行命令&#xff0c;前面相同/前后各是一个&#xff09; 注册一个网站码云、阿里云等等创建远程仓库配置SSH公钥 生成公钥 ssh-ke…

流程图怎么画?只需这几步就可以搞定!

你在工作中有没有遇到过下面这些问题&#xff1a; 思维混乱&#xff0c;想快速厘清一个项目的逻辑&#xff1b; 想让客户轻松接受自己的设计构思/产品理念等&#xff1b; 产品流程总是百密一疏&#xff0c;经常遗漏了某种用户需求&#xff1b; 想让小伙伴们快速理解一件事&…

2019年下半年教师资格证考试《综合素质》(中学)题

2.吴老师在指导青年教师时说道&#xff1a;“我们是生物老师&#xff0c;自己就知道生物的多样性和保护这种多样性的重要&#xff0c;所以对各有所长的学生&#xff0c;我们可不能做一个把学生修剪得整整齐齐的园丁。”这种说法表明教师劳动具有&#xff08; C&#xff09;。 A…

JavaScript 基础学习笔记(五):函数、作用域、匿名函数

目录 一、函数 1.1 声明和调用 1.2 形参和实参 1.3 返回值 二、作用域 2.1 全局作用域 2.2 局部作用域 三、匿名函数 3.1 函数表达式 3.2 立即执行函数 一、函数 理解函数的封装特性&#xff0c;掌握函数的语法规则 1.1 声明和调用 函数可以把具有相同或相似逻辑的代…

女性力量崛起,三八妇女节5大品牌创意案例!

随着女性意识的觉醒&#xff0c;越来越多的女性正在看见、勇敢表达自己&#xff0c;并努力提升自己、且坚定地爱自己&#xff01; 从近些年的三八妇女节主题活动中&#xff0c;我们能看到越来越多的品牌都在策划品牌、产品活动时&#xff0c;越来越注重聚焦女性成长、性别议题…

Shopify如何调取开放接口实现页面更新

Shopify提供了开放接口&#xff08;API&#xff09;&#xff0c;使开发人员能够通过编程方式与Shopify平台进行交互&#xff0c;并实现页面的更新。通过调用API&#xff0c;您可以获取和更新商店的数据&#xff0c;包括产品、订单、顾客信息等。下面是使用Shopify开放接口实现页…

【GB28181】wvp-GB28181-pro修改分屏监控为16画面(前端)

引言 作为一个非前端开发人员,自己摸索起来比较费劲,也浪费了很多时间 由于实际开发中,可能预览的画面多于8个,而wvp目前只支持8画面 本文快速帮助开发者修改分屏监控为多画面。例如16画面,20画面等 文章目录 一、 预期效果展示16分割画面20分割画面二、 源码修改-前端修改…

CV论文--2024.2.28

source:CV论文--2024.2.28 1、StreamDiffusion: A Pipeline-level Solution for Real-time Interactive Generation 中文标题&#xff1a;StreamDiffusion: 一个用于实时交互生成的管道级解决方案 简介&#xff1a;我们介绍了StreamDiffusion&#xff0c;这是专为实时交互式图…

windows IIS 申请和配置https(SSL)的工具 win-acme

win-acme 是一个为Windows平台设计的工具&#xff0c;用于从Lets Encrypt自动获取和续期SSL/TLS证书&#xff0c;特别适合用于IIS&#xff08;Internet Information Services&#xff09;服务器。它的使用相对简单&#xff0c;提供了一个用户友好的命令行界面&#xff0c;以及一…