最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實(shí)現(xiàn)百萬數(shù)據(jù)導(dǎo)出Excel的詳細(xì)指南

 更新時間:2025年07月16日 08:26:07   作者:天天摸魚的java工程師  
這篇文章主要為大家詳細(xì)介紹了使用Java語言實(shí)現(xiàn)百萬數(shù)據(jù)導(dǎo)出Excel的詳細(xì)方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

本文分享一個Java開發(fā)者從初出茅廬到技術(shù)老手的成長歷程,聚焦百萬級數(shù)據(jù)導(dǎo)出場景,看如何從OOM崩潰走向優(yōu)雅解決。

一、新手踩坑:我的第一個導(dǎo)出功能

剛?cè)胄心悄?,我接到第一個獨(dú)立任務(wù):實(shí)現(xiàn)訂單數(shù)據(jù)導(dǎo)出Excel。當(dāng)時憑著學(xué)校學(xué)的基礎(chǔ)知識,寫出了這樣的代碼:

// 新手版導(dǎo)出代碼 - 內(nèi)存炸彈!
public void exportOrders(HttpServletResponse response) {
    // 1. 一次性加載全量數(shù)據(jù)
    List<Order> allOrders = orderDao.findAll(); 
    
    // 2. 創(chuàng)建Excel對象(當(dāng)時還不知道內(nèi)存代價)
    Workbook workbook = new HSSFWorkbook();
    Sheet sheet = workbook.createSheet("Orders");
    
    // 3. 逐行填充數(shù)據(jù)
    int rowNum = 0;
    for (Order order : allOrders) {  // 百萬次循環(huán)
        Row row = sheet.createRow(rowNum++);
        row.createCell(0).setCellValue(order.getId());
        row.createCell(1).setCellValue(order.getAmount());
        // ...15+個字段
    }
    
    // 4. 寫入響應(yīng)流
    workbook.write(response.getOutputStream());
}

第一次壓測時的災(zāi)難現(xiàn)場

Exception in thread "http-nio-8080-exec-3" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3332)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
    // 堆棧指向Excel對象創(chuàng)建

二、錯誤分析:為什么新手代碼會OOM

三重內(nèi)存炸彈

  • 數(shù)據(jù)對象駐留內(nèi)存:百萬條Order對象(約1.2GB)
  • Excel DOM樹爆炸:POI的HSSFWorkbook每個單元格都是獨(dú)立對象
  • 字符串拼接黑洞:字段值拼接消耗額外內(nèi)存

內(nèi)存消耗估算

組件1萬條10萬條100萬條
訂單對象120MB1.2GB12GB
Excel對象(估算)200MB2GB20GB+
總內(nèi)存320MB3.2GB32GB+

當(dāng)時我用的測試機(jī)只有2G內(nèi)存...

三、解決之道:流式處理方案

架構(gòu)演進(jìn)對比

graph LR
    A[新手方案] -->|全內(nèi)存| B[OOM崩潰]
    C[優(yōu)化方案] -->|磁盤緩沖| D[成功導(dǎo)出]
    D -->|內(nèi)存控制| E[穩(wěn)定運(yùn)行]

核心代碼改造(基于POI SXSSF)

public void streamExport(HttpServletResponse response) throws Exception {
    // 1. 創(chuàng)建流式工作簿(內(nèi)存中只保留100行)
    Workbook workbook = new SXSSFWorkbook(100); 
    Sheet sheet = workbook.createSheet("訂單數(shù)據(jù)");
    
    // 2. 寫表頭
    Row header = sheet.createRow(0);
    header.createCell(0).setCellValue("ID");
    // ...其他表頭
    
    // 3. 分頁查詢+流式寫入
    int pageSize = 2000;
    int pageNum = 1;
    int rowIndex = 1; // 數(shù)據(jù)行起始位置
    
    while (true) {
        // 4. 分頁查詢(避免全量加載)
        List<Order> page = orderDao.findByPage(pageNum, pageSize);
        if (page.isEmpty()) break;
        
        // 5. 批量寫入當(dāng)前頁
        for (Order order : page) {
            Row row = sheet.createRow(rowIndex++);
            row.createCell(0).setCellValue(order.getId());
            // ...其他字段
        }
        
        // 6. 刷新當(dāng)前頁數(shù)據(jù)到磁盤
        ((SXSSFSheet)sheet).flushRows(page.size());
        
        pageNum++;
    }
    
    // 7. 設(shè)置響應(yīng)頭
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-Disposition", "attachment;filename=orders.xlsx");
    
    // 8. 流式輸出到客戶端
    workbook.write(response.getOutputStream());
    
    // 9. 清理臨時文件
    ((SXSSFWorkbook)workbook).dispose();
}

四、關(guān)鍵技術(shù)解析

1.SXSSFWorkbook 核心機(jī)制

滑動窗口:內(nèi)存中只保留指定行數(shù)(默認(rèn)100行)

自動刷盤:超過窗口大小的行寫入磁盤臨時文件

內(nèi)存對比:傳統(tǒng)方式 vs SXSSF

// 傳統(tǒng)方式(危險?。?
Workbook workbook = new XSSFWorkbook(); 

// 流式處理(安全)
Workbook workbook = new SXSSFWorkbook(100); 

2.分頁查詢優(yōu)化技巧

避免深度分頁:不要使用limit 1000000,100

推薦方案:基于ID范圍的連續(xù)分頁

SELECT * FROM orders WHERE id > ? ORDER BY id LIMIT 2000

3.內(nèi)存監(jiān)控技巧

添加JVM參數(shù)觀察內(nèi)存變化:

-XX:+PrintGCDetails -Xloggc:gc.log

五、性能優(yōu)化實(shí)戰(zhàn)

樣式處理陷阱

// 錯誤做法:每行創(chuàng)建樣式(內(nèi)存爆炸)
for(Order order : orders) {
    CellStyle style = workbook.createCellStyle();
    row.setCellStyle(style);
}

// 正確做法:樣式池復(fù)用
CellStyle moneyStyle = workbook.createCellStyle();
moneyStyle.setDataFormat(BuiltinFormats.getBuiltinFormat(4));

// 在需要時直接使用
cell.setCellStyle(moneyStyle);

臨時文件管理

// 自定義臨時文件位置(避免/tmp爆滿)
File tmpDir = new File("/data/tmp");
SXSSFWorkbook workbook = new SXSSFWorkbook(null, 100, true, tmpDir);

寫入加速技巧

// 批量設(shè)置單元格值(減少方法調(diào)用)
Row row = sheet.createRow(0);
Object[] values = {"ID", "金額", "日期"};
for (int i = 0; i < values.length; i++) {
    row.createCell(i).setCellValue(values[i].toString());
}

六、方案效果對比

指標(biāo)新手方案流式方案
內(nèi)存占用>3GB (OOM)≈150MB
響應(yīng)時間無法完成5分鐘/百萬行
CPU占用頻繁Full GC平穩(wěn)
代碼復(fù)雜度簡單中等
可支持?jǐn)?shù)據(jù)量<1萬行>1000萬行

七、避坑指南:血淚經(jīng)驗(yàn)

分頁查詢的坑

// MySQL深度分頁性能陷阱
List<Order> list = orderDao.query("SELECT * FROM orders LIMIT 900000,1000");

資源關(guān)閉的坑

// 忘記關(guān)閉資源導(dǎo)致內(nèi)存泄漏
Workbook workbook = new SXSSFWorkbook();
// 必須添加finally塊關(guān)閉

數(shù)據(jù)類型的坑

// 日期類型特殊處理
CellStyle dateStyle = workbook.createCellStyle();
dateStyle.setDataFormat(workbook.createDataFormat().getFormat("yyyy-MM-dd"));
cell.setCellStyle(dateStyle);

八、老鳥的思考

8年Java開發(fā)教會我處理海量數(shù)據(jù)的核心原則:

內(nèi)存有限性原則

graph LR
內(nèi)存-->磁盤-->分布式

當(dāng)內(nèi)存不夠時,合理利用磁盤空間

流式處理三要素

  • 分頁加載(Paging)
  • 批量處理(Batching)
  • 即時釋放(Releasing)

資源管理箴言

"打開的資源要及時關(guān)閉,創(chuàng)建的對象要明確生命周期"

最后建議:超過500萬行數(shù)據(jù)建議使用CSV格式或?qū)I(yè)ETL工具,Excel畢竟不是數(shù)據(jù)庫!

以上就是Java實(shí)現(xiàn)百萬數(shù)據(jù)導(dǎo)出Excel的詳細(xì)指南的詳細(xì)內(nèi)容,更多關(guān)于Java百萬數(shù)據(jù)導(dǎo)出Excel的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 關(guān)于elasticsearch的match_phrase_prefix查詢詳解

    關(guān)于elasticsearch的match_phrase_prefix查詢詳解

    這篇文章主要介紹了關(guān)于elasticsearch的match_phrase_prefix查詢問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • new出來的對象中無法使用@autowired進(jìn)行對象bean注入問題

    new出來的對象中無法使用@autowired進(jìn)行對象bean注入問題

    這篇文章主要介紹了基于new出來的對象中無法使用@autowired進(jìn)行對象bean注入問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Spring IOC創(chuàng)建對象的兩種方式

    Spring IOC創(chuàng)建對象的兩種方式

    這篇文章主要給大家介紹了關(guān)于Spring IOC創(chuàng)建對象的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Java?面向?qū)ο缶幊讨衧tatic關(guān)鍵字的深度剖析與實(shí)踐

    Java?面向?qū)ο缶幊讨衧tatic關(guān)鍵字的深度剖析與實(shí)踐

    在?Java?面向?qū)ο缶幊痰凝嫶篌w系中,?static關(guān)鍵字作為一項(xiàng)極為重要的特性,對代碼的設(shè)計(jì)、組織和性能有著深遠(yuǎn)的影響,本文將深入探討static關(guān)鍵字在靜態(tài)變量、靜態(tài)方法和工具類設(shè)計(jì)中的應(yīng)用,并剖析其中的關(guān)鍵要點(diǎn)與注意事項(xiàng),感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • 初識sa-token及登錄授權(quán)簡單實(shí)現(xiàn)

    初識sa-token及登錄授權(quán)簡單實(shí)現(xiàn)

    這篇文章主要為大家介紹了sa-token及登錄授權(quán)簡單實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 使用postman傳遞list集合后臺springmvc接收

    使用postman傳遞list集合后臺springmvc接收

    這篇文章主要介紹了使用postman傳遞list集合后臺springmvc接收的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java圖片縮放實(shí)現(xiàn)圖片填充整個屏幕

    java圖片縮放實(shí)現(xiàn)圖片填充整個屏幕

    這篇文章主要介紹了java圖片縮放實(shí)現(xiàn)圖片填充整個屏幕,本文提供了兩種解決方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Java創(chuàng)建型設(shè)計(jì)模式之工廠方法模式深入詳解

    Java創(chuàng)建型設(shè)計(jì)模式之工廠方法模式深入詳解

    工廠方法模式(FACTORY METHOD)是一種常用的類創(chuàng)建型設(shè)計(jì)模式,此模式的核心精神是封裝類中變化的部分,提取其中個性化善變的部分為獨(dú)立類,通過依賴注入以達(dá)到解耦、復(fù)用和方便后期維護(hù)拓展的目的。它的核心結(jié)構(gòu)有四個角色,分別是抽象工廠、具體工廠、抽象產(chǎn)品、具體產(chǎn)品
    2022-09-09
  • Kotlin語法學(xué)習(xí)-變量定義、函數(shù)擴(kuò)展、Parcelable序列化等簡單總結(jié)

    Kotlin語法學(xué)習(xí)-變量定義、函數(shù)擴(kuò)展、Parcelable序列化等簡單總結(jié)

    這篇文章主要介紹了Kotlin語法學(xué)習(xí)-變量定義、函數(shù)擴(kuò)展、Parcelable序列化等簡單總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • java實(shí)現(xiàn)檢測Linux網(wǎng)絡(luò)狀態(tài)(附源碼)

    java實(shí)現(xiàn)檢測Linux網(wǎng)絡(luò)狀態(tài)(附源碼)

    實(shí)時監(jiān)控服務(wù)器網(wǎng)絡(luò)狀態(tài)是保證業(yè)務(wù)高可用性和可靠性的重要環(huán)節(jié),本文主要介紹了如何設(shè)計(jì)并實(shí)現(xiàn)一個高性能,可擴(kuò)展,支持事件訂閱與周期采樣的Linux?網(wǎng)絡(luò)狀態(tài)檢測工具,需要的可以了解下
    2025-06-06

最新評論

尼玛县| 毕节市| 镇康县| 公主岭市| 彭泽县| 漳浦县| 四子王旗| 莱州市| 绩溪县| 井冈山市| 滁州市| 彭泽县| 海林市| 岳普湖县| 唐海县| 华阴市| 旌德县| 彰化市| 黔西| 怀化市| 福清市| 绿春县| 来安县| 甘肃省| 乌拉特中旗| 永城市| 临西县| 连平县| 大埔区| 江西省| 精河县| 江阴市| 汕尾市| 娄烦县| 金华市| 双柏县| 长阳| 西乌珠穆沁旗| 兴安县| 安塞县| 哈密市|