Java中优化大量数据导出到Excel的内存消耗(三):边读边写

news2024/9/20 22:28:18

优化大量数据导出到Excel的内存消耗(二):如果数据超出Excel单表上限,则进行分表_txt导入excel超出最大行如何自动分表-CSDN博客

数据导出进行边读边写excel方式导出

DataSource dataSource = dataSourceService.getByDsName(requestObj.getString("dsName"));
QuerySqlVO querySqlVO = modelNativeService.buildQuerySQL(requestObj,dataSource);
                     
this.queryDataAndWriteExcel(wb,header,querySqlVO,impRelation.getLabel(),currentSheetNum);
/**
 * 查询数据并写入到Excel文件中。
 *
 * @param wb         已经存在的SXSSFWorkbook对象,用于写入数据。
 * @param header     表头信息,键为字段名,值为表头显示的文字。
 * @param querySqlVO 包含查询SQL语句、参数和数据源信息的对象。
 * @param label      用于标识Sheet的标签前缀。
 * @param sheetNum   当前Sheet的编号。
 * @return 写入数据后的SXSSFWorkbook对象。
 * @throws SQLException 如果数据库操作出现异常。
 */
public SXSSFWorkbook queryDataAndWriteExcel(SXSSFWorkbook wb, Map<String, String> header,
                                            QuerySqlVO querySqlVO, String label, int sheetNum) throws SQLException {
    // 创建一个新的Sheet,并设置其名称
    Sheet sheet = wb.createSheet(label + "_" + sheetNum);

    // 初始化行号
    int rowNum = 0;
    // 创建第一行用于写入表头
    Row row = sheet.createRow(rowNum);
    // 初始化列号
    int cellNum = 0;
    // 遍历表头信息并写入第一行
    for (Map.Entry<String, String> entry : header.entrySet()) {
        String fieldDesc = entry.getValue();
        row.createCell(cellNum).setCellValue(fieldDesc);
        cellNum++;
    }

    // 获取查询参数
    Map<String, Object> sqlParams = querySqlVO.getSqlParams();
    // 获取查询SQL语句
    String querySQL = querySqlVO.getQuerySql();
    // 获取数据源
    DataSource dataSource = querySqlVO.getDataSource();

    // 设置数据源名称
    DataSourceDefinition.setName(SunimpConsts.getDsRegisterName(dataSource.getDsName()));

    // 执行计数查询
    Long total = commonService.countLogicSql(querySQL, sqlParams);

    // 如果查询结果不为空且大于0,则继续执行
    if (ObjectKit.isNotEmpty(total) && total > 0) {

        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        ResultSetMetaData meta = null;
        try {
            // 日志输出查询SQL语句
            logger.info("readAndWriteToData sql:{}", querySQL);

            // 替换SQL语句中的参数占位符
            for (String key : sqlParams.keySet()) {
                Object value = sqlParams.get(key);
                String fieldKey = "#{" + key + "}";
                if (value instanceof Integer) {
                    querySQL = querySQL.replace(fieldKey, String.valueOf(value));
                } else {
                    querySQL = querySQL.replace(fieldKey, "'" + String.valueOf(value) + "'");
                }
            }

            // 日志输出替换参数后的SQL语句
            logger.info("readAndWriteToData sql1:{}", querySQL);
            // 日志输出查询参数的JSON形式
            logger.info("JOSN sql:{}", JSON.toJSONString(sqlParams));

            // 获取数据源信息
            DataSourceInfo sourceInfo = DataSourceDefinition.getDataSourceInfo();
            // 建立数据库连接
            conn = DataSourceDefinition.getDataSource().getConnection();
            // 准备执行SQL语句
            ps = conn.prepareStatement(querySQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);

            // 设置每次获取的数据量
            int fetchSize = 2000;
            if ("POSTGRESQL".equalsIgnoreCase(sourceInfo.getDsType())) {
                conn.setAutoCommit(false);
                ps.setFetchSize(fetchSize);
            } else if ("MYSQL".equalsIgnoreCase(sourceInfo.getDsType())) {
                ps.setFetchSize(Integer.MIN_VALUE);
                ps.setFetchDirection(ResultSet.FETCH_REVERSE);
            } else {
                ps.setFetchSize(fetchSize);
            }

            // 执行查询
            rs = ps.executeQuery();
            // 获取元数据
            meta = rs.getMetaData();
            // 存储查询结果
            List<Map<String, Object>> data = new ArrayList<>();

            // 初始化行号
            int num = 0;
            // 循环读取查询结果
            while (rs.next()) {
                // 如果行数超过100万,则创建新的Sheet
                if (rowNum >= 1000000) {
                    sheetNum++;
                    sheet = wb.createSheet(label + "_" + sheetNum);

                    // 重置行号
                    rowNum = 0;
                    // 创建新Sheet的第一行
                    row = sheet.createRow(rowNum);

                    // 重置列号
                    cellNum = 0;
                    // 再次写入表头
                    for (Map.Entry<String, String> entry : header.entrySet()) {
                        String fieldDesc = entry.getValue();
                        row.createCell(cellNum).setCellValue(fieldDesc);
                        cellNum++;
                    }
                }
                // 增加行号
                rowNum++;
                // 创建新行
                row = sheet.createRow(rowNum);

                // 重置列号
                cellNum = 0;

                // 获取列数
                int length = meta.getColumnCount();
                // 创建一行数据的Map
                Map<String, Object> rowMap = new LinkedHashMap<>();
                // 遍历每一列
                for (int i = 1; i <= length; i++) {
                    String columnName = meta.getColumnName(i).toUpperCase();
                    rowMap.put(columnName, rs.getObject(i));
                }

                // 遍历表头信息,写入数据
                for (Map.Entry<String, String> entry : header.entrySet()) {
                    String fieldName = entry.getKey();
                    Object fieldValue = rowMap.get(fieldName.toLowerCase());
                    // 结果表在不同的数据库时,字段有可能为大写
                    if (ObjectKit.isEmpty(fieldValue)) {
                        fieldValue = rowMap.get(fieldName.toUpperCase());
                    }
                    row.createCell(cellNum).setCellValue(null == fieldValue ? "" : fieldValue.toString());
                    cellNum++;
                }

                // 每处理10000条记录输出一次日志
                num++;
                if (num % 10000 == 0) {
                    logger.info("conn meta meta ------------write-----:{}", num);
                }
            }
            // 处理完毕后输出日志
            logger.info("conn meta meta ------------end-----:{}", num);
        } catch (Exception e) {
            throw e;
        } finally {
            // 关闭资源
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    logger.warn("close Connection error", e);
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    logger.warn("close Statement error", e);
                }
            }
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.warn("close ResultSet error", e);
                }
            }
            // 清空数据源名称
            DataSourceDefinition.setName(null);
        }
    }
    // 返回写入数据后的SXSSFWorkbook对象
    return wb;
}

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

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

相关文章

二手车交易系统功能案例分析

一、系统概述 二手车交易系统旨在连接卖家与买家&#xff0c;提供车辆信息发布、搜索、评估、交易、支付及售后服务等一站式解决方案。该系统需具备高度的可扩展性、稳定性和安全性&#xff0c;以满足日益增长的市场需求。 二、核心功能分析 1. 车辆信息发布与管理 功能描述…

三维坐标的旋转矩阵转换测试Demo(ROS1 RVIZ)

已知空间上的某一个点P在坐标系1下的位置为 P1&#xff08;1,2,3&#xff09;&#xff0c;需要求出P在三维空间坐标系0之间的相对关系&#xff0c;其中坐标系1是相对于坐标系0绕着x轴旋转60度后转化。示意如下图 程序设计 定义P点在坐标系1下的位置 array np.array([1,2,3…

vscode开发android ndk的环境配置

vscode开发android ndk的环境配置 最近公司新需求&#xff0c;要求用C/C实现部分核心代码&#xff0c;打包成静态库跨平台&#xff08;Android和iOS&#xff09;使用。 作为Android开发出身的C/C老白程序员兴奋不已&#xff08;又可以开心的学习niubility的C/C了&#xff09;&…

SpringCloudAlibaba基础七-2 seata的使用

一 Seata 是什么 Seata 是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和XA 事务模式&#xff0c;为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS&#x…

pycharm创建文件自动生成文件头信息

pycharm创建文件自动生成文件头信息 1、设置步骤 file -> settings->Editor->File and Code Templates->Python Script 2、pycharm预定义的变量&#xff08;小写无效&#xff09; ${PROJECT_NAME}:项目名称${PRODUCT_NAME}:集成开发环境${NAME}:文件名${USER…

高效工作与持续学习:程序员如何平衡成长与编码任务?

在当今瞬息万变的技术世界中&#xff0c;程序员面临着前所未有的挑战和机遇。随着项目复杂性的增加和新技术的层出不穷&#xff0c;如何在繁忙的日常编码任务与自我提升之间找到平衡&#xff0c;已成为许多程序员心中的困惑。这不仅关乎职业生涯的发展&#xff0c;更关系到个人…

Transformer系列-3丨BERT模型和代码解析

1 前言 前面两篇文章&#xff0c;笔者从网络结构和代码实现角度较为深入地和大家解析了Transformer模型和Vision Transformer模型&#xff08;ViT&#xff09;&#xff0c;其具体的链接如下&#xff1a; 基础Transformer解析 ViT模型与代码解析 本期内容&#xff0c;笔者想…

贪心+构造,CF 1592F1 - Alice and Recoloring 1

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 1592F1 - Alice and Recoloring 1 二、解题报告 1、思路分析 操作2、3可以…

C++系列-多态的基本语法

多态的基本语法 多态的含义静态多态动态多态 多态的底层原理多态中的final和overridefinaloverride: 多态的应用和优点计算器简单实现电脑组装的实现 《游山西村》 南宋陆游 莫笑农家腊酒浑&#xff0c;丰年留客足鸡豚。 山重水复疑无路&#xff0c;柳暗花明又一村。 箫鼓追…

leetcode118. 杨辉三角,老题又做

leetcode118. 杨辉三角 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 输入: numRows 1…

AI视频创作应用

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…

appium下载及安装

下载地址&#xff1a;https://github.com/appium/appium-desktop/releases 双击安装就可以

信号的变换

信号的变换 在实践中&#xff0c;缩放和时间平移是遇到的两个最重要的信号变换。缩放改变了振幅轴上的因变量的值&#xff0c;而时间平移则影响了时间轴上的自变量的值。 加法 对于两个离散时间信号的加法&#xff0c;例如 x [ n ] x[n] x[n] 和 y [ n ] y[n] y[n]&#x…

Flutter【02】mobx原理

简介&#xff1a; 概念 MobX 区分了以下几个应用中的概念&#xff1a; State(状态) 状态 是驱动应用的数据。 通常有像待办事项列表这样的领域特定状态&#xff0c;还有像当前已选元素的视图状态。 记住&#xff0c;状态就像是有数据的excel表格。 Derivations(衍生) 任何…

Ps:首选项 - 性能

Ps菜单&#xff1a;编辑/首选项 Edit/Preferences 快捷键&#xff1a;Ctrl K Photoshop 首选项中的“性能” Performance选项卡允许用户通过调整内存使用、GPU 设置、高速缓存设置以及多线程处理等选项&#xff0c;来优化 Photoshop 的性能。这对于处理大文件、复杂图像或需要…

Python 数据分析之Numpy学习(一)

Python 数据分析之Numpy学习&#xff08;一&#xff09; 一、Numpy的引入 1.1 矩阵/向量的按位运算 需求&#xff1a;矩阵的按位相加 [0,1,4] [0,1,8] [0,2,12] 1.1.1 利用python实现矩阵/向量的按位运算 # 1.通过列表实现 list1 [0, 1, 4] list2 [0, 1, 8]# 列表使用…

(17)ELK大型储存库的搭建

前言&#xff1a; els是大型数据储存体系&#xff0c;类似于一种分片式存储方式。elasticsearch有强大的查询功能&#xff0c;基于java开发的工具&#xff0c;结合logstash收集工具&#xff0c;收集数据。kibana图形化展示数据&#xff0c;可以很好在大量的消息中准确的找到符…

Marimo:下一代Python编程环境,颠覆传统Jupyter笔记本,自动化执行所有依赖代码块,告别繁琐手动操作

Marimo 是一个颠覆传统笔记本的全新编程环境&#xff0c;它以其反应式、交互式、可执行和可共享等特性&#xff0c;为开发者们带来前所未有的编程体验。Marimo 确保您的笔记本代码、输出和程序状态始终保持一致。它解决了传统笔记本&#xff08;如 Jupyter&#xff09;的许多问…

流媒体服务器如何让WebRTC支持H.265,同时又能支持Web js硬解码、软解码(MSE硬解、WASM软解)

为了这一整套的解决方案&#xff0c;调研研发整整花费了差不多半年多的时间&#xff0c;需达成的目标&#xff1a; 流媒体服务器端不需要将H.265转码成H.264&#xff0c;就能让Chrome解码播放H.265&#xff1b; 注意&#xff1a;现在很多市面上的软硬件通过转码H.265成H.264的…

CSP-CCF 202312-1 仓库规划

一、问题描述 二、解答 思路&#xff1a;定义二维数组&#xff0c;比较不同行的相同列数 代码如下&#xff1a; #include<iostream> using namespace std; int main() {int n, m;cin >> n >> m;int a[1001][11] { 0 };for (int i 1; i < n; i){for (…