java查询一次性查询几十万,几百万数据解决办法(转)

本文介绍了一种使用Java批量查询数据库中几十万甚至几百万条数据的方法。通过将数据分批查询并存储到本地文件中,再利用内存映射文件进行高效读取,解决了大数据量查询效率低的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java查询一次性查询几十万,几百万数据解决办法

很早的时候写工具用的一个办法。

当时是用来把百万数据打包 成rar文件。

所以用了个笨办法。 希望高手指导一下,有什么好方法没有啊


1、先批量查出所有数据,例子中是一万条一批。
2、在查出数据之后把每次的数据按一定规则存入本地文件。
3、获取数据时,通过批次读取,获得大批量数据。此方法参见:http://yijianfengvip.blog.163.com/blog/static/175273432201191354043148/

以下是查询数据库。按批次查询
public static void  getMonthDataList() {
        ResultSet rs = null;
        Statement stat = null;
        Connection conn = null;
        List<DataBean> list = new ArrayList<DataBean>();
        try {
            conn = createConnection();
            if(conn!=null){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                SimpleDateFormat timesdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String nowDate = sdf.format(new Date());
                Config.lasttimetext = timesdf.format(new Date());
                String lastDate = sdf.format(CreateData.addDaysForDate(new Date(), 30));
                stat = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
                int lastrow = 0;
                int datanum = 0;
                String countsql = "SELECT count(a.id) FROM trip_special_flight a" +
                " where a.dpt_date >= to_date('"+nowDate+"','yyyy-mm-dd') " +
                "and a.dpt_date <= to_date('"+lastDate+"','yyyy-mm-dd') and rownum>"+lastrow+" order by a.get_time  desc";
                rs = stat.executeQuery(countsql);
                while (rs.next()) {
                    datanum = rs.getInt(1);
                }
                int onerun = 10000;
                int runnum = datanum%onerun==0?(datanum/onerun):(datanum/onerun)+1;
                for(int r =0;r<runnum;r++){
                    System.out.println("getMonthDataList--"+datanum+" 开始查询第"+(r+1)+"批数据");
                    String sql = "SELECT * FROM  (SELECT rownum rn, a.dpt_code, a.arr_code,a.dpt_date,a.airways,a.flight," +
                    "a.cabin,a.price FROM trip_special_flight a" +
                    " where a.dpt_date >= to_date('"+nowDate+"','yyyy-mm-dd') " +
                    "and a.dpt_date <= to_date('"+lastDate+"','yyyy-mm-dd')  order by rownum  asc) WHERE rn > "+lastrow;
                    stat.setMaxRows(onerun);
                    stat.setFetchSize(1000);
                    rs = stat.executeQuery(sql);
                    String text = "";
                    int i = 1;
                    while (rs.next()) {
                        text += rs.getString(2)+"|"+rs.getString(3)+"|"+rs.getDate(4)+"|"+rs.getString(5)+"|"+rs.getString(6)+"|"+rs.getString(7)+"|"+rs.getString(8)+"||";
                        if(i%1000==0){
                            FileUtil.appendToFile(Config.tempdatafile, text);
                            text = "";
                        }
                        i++;
                    }
                    if(text.length()>10){
                        FileUtil.appendToFile(Config.tempdatafile, text);
                    }
                    lastrow+=onerun;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeAll(rs, stat, conn);
        }
    }
 

-----java一次性查询几十万,几百万数据解决办法

 

 

存入临时文件之后,再用读取大量数据文件方法。

 

设置缓存大小BUFFER_SIZE ,Config.tempdatafile是文件地址

来源博客http://yijianfengvip.blog.163.com/blog/static/175273432201191354043148/

 

package com.yjf.util;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Test {
    public static void main(String[] args) throws Exception {
        final int BUFFER_SIZE = 0x300000; // 缓冲区为3M
        File f = new File(Config.tempdatafile);
 //  来源博客http://yijianfengvip.blog.163.com/blog/static/175273432201191354043148/
        int len = 0;
        Long start = System.currentTimeMillis();
        for (int z = 8; z >0; z--) {
            MappedByteBuffer inputBuffer = new RandomAccessFile(f, "r")
                    .getChannel().map(FileChannel.MapMode.READ_ONLY,
                            f.length() * (z-1) / 8, f.length() * 1 / 8);
            byte[] dst = new byte[BUFFER_SIZE];// 每次读出3M的内容
            for (int offset = 0; offset < inputBuffer.capacity(); offset += BUFFER_SIZE) {
                if (inputBuffer.capacity() - offset >= BUFFER_SIZE) {
                    for (int i = 0; i < BUFFER_SIZE; i++)
                        dst[i] = inputBuffer.get(offset + i);
                } else {
                    for (int i = 0; i < inputBuffer.capacity() - offset; i++)
                        dst[i] = inputBuffer.get(offset + i);
                }
                int length = (inputBuffer.capacity() % BUFFER_SIZE == 0) ? BUFFER_SIZE
                        : inputBuffer.capacity() % BUFFER_SIZE;
                len += new String(dst, 0, length).length();
                System.out.println(new String(dst, 0, length).length()+"-"+(z-1)+"-"+(8-z+1));
            }
        }
        System.out.println(len);
        long end = System.currentTimeMillis();
        System.out.println("读取文件文件花费:" + (end - start) + "毫秒");
    }
}
 
读取大量数据文件方法。
<think>好的,我现在需要帮用户解决如何使用EasyExcel生成包含几十万数据的大XLSX文件的问题。用户之前可能已经了解过EasyExcel的优势,比如内存优化,但现在需要具体的实现步骤和最佳实践。首先,我得回顾一下用户提供的引用内容,确保回答符合他们的需求。 根据引用[1]和[3],EasyExcel在处理大数据时通过重写POI的解析方式,显著降低了内存使用,适合导出百万级数据。用户提到几十万条,虽然不算极端,但仍需注意内存管理。引用[2]提到压缩导出时的Stream closed异常,但用户的问题主要是生成单个文件,这部分可能暂时不需要,但可以留作后续扩展。引用[4]和[5]分别涉及模板生成和解析,但用户现在关注的是导出,所以重点在导出流程。 接下来,我需要整理最佳实践的步骤。首先,分页查询数据是关键,避免一次性加载所有数据到内存,这符合引用[3]中的分页处理建议。然后,使用EasyExcel的WriteSheet和异步写入功能,这能进一步减少内存占用。另外,临时文件的使用也很重要,因为直接写入流可能在网络中断时失败,而临时文件可以确保数据完整性。 在代码示例部分,需要展示如何分页查询,配置ExcelWriter,以及逐页写入数据。同时,要提到模板导出和样式优化,比如禁用默认样式和设置自动列宽,这些都能提升性能和用户体验。最后,异常处理和资源清理也是必要步骤,防止资源泄漏。 可能还需要考虑用户的其他潜在问题,比如如何处理特殊数据类型,或者如何优化查询速度。不过根据当前问题,重点应放在导出流程和内存管理上。需要确保代码示例正确,并解释每一步的作用,让用户清楚最佳实践的原因。另外,引用相关的引用文献作为支持,比如引用[1]和[3]来强调内存优化的有效性。</think>以下是如何使用EasyExcel高效生成包含几十万数据的XLSX文件的逐步解决方案: ### 一、核心实现步骤 1. **分页查询数据** - 采用分段加载策略,每次查询5000-10000条数据 - 避免一次性加载全部数据到内存中,防止OOM[^3] ```java public List<DataEntity> queryDataByPage(int pageNo, int pageSize) { // 实际需替换为分页SQL查询 return dataMapper.selectPage((pageNo-1)*pageSize, pageSize); } ``` 2. **配置ExcelWriter** ```java // 使用try-with-resources确保资源释放 try (ExcelWriter excelWriter = EasyExcel.write(fileName, DataEntity.class) .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) .build()) { WriteSheet writeSheet = EasyExcel.writerSheet("数据列表").build(); int pageSize = 10000; for (int pageNo = 1; ; pageNo++) { List<DataEntity> dataChunk = queryDataByPage(pageNo, pageSize); if (dataChunk.isEmpty()) break; excelWriter.write(dataChunk, writeSheet); dataChunk.clear(); // 及时释放内存 } } ``` ### 二、关键优化策略 1. **内存控制技术** - 使用`SXSSF`模式(自动启用) - 默认保留100条数据在内存,超出部分写入临时文件[^1] - 调整窗口大小:`.withTempFileWindowSize(500)` 2. **写入方式选择** ```java // 推荐使用异步写入(默认开启) .inMemory(false) // 设置临时文件存储路径 .tempFile(new File("/data/temp")) ``` ### 三、最佳实践建议 1. **模板导出优化** ```java // 复用模板样式(引用[4]) ExcelWriter writer = EasyExcel.write(outStream) .withTemplate(templateFile) .registerWriteHandler(new CellStyleStrategy()) .build(); ``` 2. **性能优化配置** - 禁用默认样式:`.ignoreHeadStyle()` - 关闭自动合并:`.autoTrim(false)` - 设置自动列宽:`.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())` ### 四、异常处理 ```java try { // 写入逻辑 } catch (ExcelGenerateException e) { log.error("Excel生成异常", e); // 清理临时文件 } finally { if (excelWriter != null) { excelWriter.finish(); } // 删除临时文件 } ``` ### 五、扩展方案 1. **海量数据分文件存储** - 每50万条生成一个sheet - 超过100万条生成新文件[^2] ```java if (totalCount % 1000000 == 0) { excelWriter.finish(); createNewWriter(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值