色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

excel導出功能如何實現?

jf_78858299 ? 來源:蘇三說技術 ? 作者:蘇三說技術 ? 2023-05-11 18:17 ? 次閱讀

前言

最近我做過一個MySQL百萬級別數據的excel導出功能,已經正常上線使用了。

這個功能挺有意思的,里面需要注意的細節還真不少,現在拿出來跟大家分享一下,希望對你會有所幫助。

原始需求:用戶在UI界面上點擊全部導出按鈕,就能導出所有商品數據。

咋一看,這個需求挺簡單的。

但如果我告訴你,導出的記錄條數,可能有一百多萬,甚至兩百萬呢?

這時你可能會倒吸一口氣。

因為你可能會面臨如下問題:

  1. 如果同步導數據,接口很容易超時。
  2. 如果把所有數據一次性裝載到內存,很容易引起OOM。
  3. 數據量太大sql語句必定很慢。
  4. 相同商品編號的數據要放到一起。
  5. 如果走異步,如何通知用戶導出結果?
  6. 如果excel文件太大,目標用戶打不開怎么辦?

我們要如何才能解決這些問題,實現一個百萬級別的excel數據快速導出功能呢?

圖片

1.異步處理

做一個MySQL百萬數據級別的excel導出功能,如果走接口同步導出,該接口肯定會非常容易超時

因此,我們在做系統設計的時候,第一選擇應該是接口走異步處理。

說起異步處理,其實有很多種,比如:使用開啟一個線程,或者使用線程池,或者使用job,或者使用mq等。

為了防止服務重啟時數據的丟失問題,我們大多數情況下,會使用job或者mq來實現異步功能。

1.1 使用job

如果使用job的話,需要增加一張執行任務表,記錄每次的導出任務。

用戶點擊全部導出按鈕,會調用一個后端接口,該接口會向表中寫入一條記錄,該記錄的狀態為:待執行

有個job,每隔一段時間(比如:5分鐘),掃描一次執行任務表,查出所有狀態是待執行的記錄。

然后遍歷這些記錄,挨個執行。

需要注意的是:如果用job的話,要避免重復執行的情況。比如job每隔5分鐘執行一次,但如果數據導出的功能所花費的時間超過了5分鐘,在一個job周期內執行不完,就會被下一個job執行周期執行。

所以使用job時可能會出現重復執行的情況。

為了防止job重復執行的情況,該執行任務需要增加一個執行中的狀態。

具體的狀態變化如下:

  1. 執行任務被剛記錄到執行任務表,是待執行狀態。
  2. 當job第一次執行該執行任務時,該記錄再數據庫中的狀態改為:執行中
  3. 當job跑完了,該記錄的狀態變成:完成失敗

這樣導出數據的功能,在第一個job周期內執行不完,在第二次job執行時,查詢待處理狀態,并不會查詢出執行中狀態的數據,也就是說不會重復執行。

此外,使用job還有一個硬傷即:它不是立馬執行的,有一定的延遲。

如果對時間不太敏感的業務場景,可以考慮使用該方案。

1.2 使用mq

用戶點擊全部導出按鈕,會調用一個后端接口,該接口會向mq服務端,發送一條mq消息

有個專門的mq消費者,消費該消息,然后就可以實現excel的數據導出了。

相較于job方案,使用mq方案的話,實時性更好一些。

對于mq消費者處理失敗的情況,可以增加補償機制,自動發起重試

RocketMQ自帶了失敗重試功能,如果失敗次數超過了一定的閥值,則會將該消息自動放入死信隊列

2.使用easyexcel

我們知道在Java中解析和生成Excel,比較有名的框架有Apache POIjxl

但它們都存在一個嚴重的問題就是:非常耗內存,POI有一套SAX模式的API可以一定程度的解決一些內存溢出的問題,但POI還是有一些缺陷,比如07版Excel解壓縮以及解壓后存儲都是在內存中完成的,內存消耗依然很大。

百萬級別的excel數據導出功能,如果使用傳統的Apache POI框架去處理,可能會消耗很大的內存,容易引發OOM問題。

easyexcel重寫了POI對07版Excel的解析,之前一個3M的excel用POI sax解析,需要100M左右內存,如果改用easyexcel可以降低到幾M,并且再大的Excel也不會出現內存溢出;03版依賴POI的sax模式,在上層做了模型轉換的封裝,讓使用者更加簡單方便。

需要在mavenpom.xml文件中引入easyexcel的jar包:

<dependency>
    <groupId>com.alibaba<span class="hljs-name"groupId>
    <artifactId>easyexcel<span class="hljs-name"artifactId>
    <version>3.0.2<span class="hljs-name"version>
<span class="hljs-name"dependency>

之后,使用起來非常方便。

讀excel數據非常方便:

@Test
public void simpleRead() {
    String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
    // 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關閉
    EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}

寫excel數據也非常方便:

@Test
public void simpleWrite() {
    String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx";
    // 這里 需要指定寫用哪個class去讀,然后寫到第一個sheet,名字為模板 然后文件流會自動關閉
    // 如果這里想使用03 則 傳入excelType參數即可
    EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
}

easyexcel能大大減少占用內存的主要原因是:在解析Excel時沒有將文件數據一次性全部加載到內存中,而是從磁盤上一行行讀取數據,逐個解析。

3.分頁查詢

百萬級別的數據,從數據庫一次性查詢出來,是一件非常耗時的工作。

即使我們可以從數據庫中一次性查詢出所有數據,沒出現連接超時問題,這么多的數據全部加載到應用服務的內存中,也有可能會導致應用服務出現OOM問題。

因此,我們從數據庫中查詢數據時,有必要使用分頁查詢。比如:每頁5000條記錄,分為200頁查詢。

public Page<User> searchUser(SearchModel searchModel) {
    List<User> userList = userMapper.searchUser(searchModel);
    Page<User> pageResponse = Page.create(userList, searchModel);
    pageResponse.setTotal(userMapper.searchUserCount(searchModel));
    return pageResponse;
}

每頁大小pageSize和頁碼pageNo,是SearchModel類中的成員變量,在創建searchModel對象時,可以設置設置這兩個參數。

然后在Mybatis的sql文件中,通過limit語句實現分頁功能:

limit #{pageStart}, #{pageSize}

其中的pagetStart參數,是通過pageNo和pageSize動態計算出來的,比如:

pageStart = (pageNo - 1) * pageSize;

4.多個sheet

我們知道,excel對一個sheet存放的最大數據量,是有做限制的,一個sheet最多可以保存1048576行數據。否則在保存數據時會直接報錯:

invalid row number (1048576) outside allowable range (0..1048575)

如果你想導出一百萬以上的數據,excel的一個sheet肯定是存放不下的。圖片

因此我們需要把數據保存到多個sheet中。圖片

5.計算limit的起始位置

我之前說過,我們一般是通過limit語句來實現分頁查詢功能的:

limit #{pageStart}, #{pageSize}

其中的pagetStart參數,是通過pageNo和pageSize動態計算出來的,比如:

pageStart = (pageNo - 1) * pageSize;

如果只有一個sheet可以這么玩,但如果有多個sheet就會有問題。因此,我們需要重新計算limit的起始位置。

例如:

ExcelWriter excelWriter = EasyExcelFactory.write(out).build();
int totalPage = searchUserTotalPage(searchModel);

if(totalPage > 0) {
   Page<User> page = Page.create(searchModel);
   int sheet = (totalPage % maxSheetCount == 0) ? totalPage / maxSheetCount: (totalPage / maxSheetCount) + 1;
   for(int i=0;i

這樣就能實現分頁查詢,將數據導出到不同的excel的sheet當中。

6.文件上傳到OSS

由于現在我們導出excel數據的方案改成了異步,所以沒法直接將excel文件,同步返回給用戶。

因此我們需要先將excel文件存放到一個地方,當用戶有需要時,可以訪問到。

這時,我們可以直接將文件上傳到OSS文件服務器上。

通過OSS提供的上傳接口,將excel上傳成功后,會返回文件名稱訪問路徑

我們可以將excel名稱和訪問路徑保存到中,這樣的話,后面就可以直接通過瀏覽器,訪問遠程excel文件了。

而如果將excel文件保存到應用服務器,可能會占用比較多的磁盤空間

一般建議將應用服務器文件服務器分開,應用服務器需要更多的內存資源或者CPU資源,而文件服務器需要更多的磁盤資源

7.通過WebSocket推送通知

通過上面的功能已經導出了excel文件,并且上傳到了OSS文件服務器上。

接下來的任務是要本次excel導出結果,成功還是失敗,通知目標用戶。

有種做法是在頁面上提示:正在導出excel數據,請耐心等待

然后用戶可以主動刷新當前頁面,獲取本地導出excel的結果。

但這種用戶交互功能,不太友好。

還有一種方式是通過webSocket建立長連接,進行實時通知推送。

如果你使用了SpringBoot框架,可以直接引入webSocket的相關jar包:

<dependency>
  <groupId>org.springframework.boot<span class="hljs-name"groupId>
  <artifactId>spring-boot-starter-websocket<span class="hljs-name"artifactId>
<span class="hljs-name"dependency>

使用起來挺方便的。

我們可以加一張專門的通知表,記錄通過webSocket推送的通知的標題、用戶、附件地址、閱讀狀態、類型等信息

能更好的追溯通知記錄。

webSocket給客戶端推送一個通知之后,用戶的右上角的收件箱上,實時出現了一個小窗口,提示本次導出excel功能是成功還是失敗,并且有文件下載鏈接。

當前通知的閱讀狀態是未讀

用戶點擊該窗口,可以看到通知的詳細內容,然后通知狀態變成已讀

8.總條數可配置

我們在做導百萬級數據這個需求時,是給用戶用的,也有可能是給運營同學用的。

其實我們應該站在實際用戶的角度出發,去思考一下,這個需求是否合理。

用戶拿到這個百萬級別的excel文件,到底有什么用途,在他們的電腦上能否打開該excel文件,電腦是否會出現太大的卡頓了,導致文件使用不了。

如果該功能上線之后,真的發生發生這些情況,那么導出excel也沒有啥意義了。

因此,非常有必要把記錄的總條數,做成可配置的,可以根據用戶的實際情況調整這個配置。

比如:用戶發現excel中有50萬的數據,可以正常訪問和操作excel,這時候我們可以將總條數調整成500000,把多余的數據截取掉。

其實,在用戶的操作界面,增加更多的查詢條件,用戶通過修改查詢條件,多次導數據,可以實現將所有數據都導出的功能,這樣可能更合理一些。

此外,分頁查詢時,每頁的大小,也建議做成可配置的。

通過總條數和每頁大小,可以動態調整記錄數量和分頁查詢次數,有助于更好滿足用戶的需求。

9.order by商品編號

之前的需求是要將相同商品編號的數據放到一起。

例如:

編號 商品名稱 倉庫名稱 價格
1 筆記本 北京倉 7234
1 筆記本 上海倉 7235
1 筆記本 武漢倉 7236
2 平板電腦 成都倉 7236
2 平板電腦 大連倉 3339

但我們做了分頁查詢的功能,沒法將數據一次性查詢出來,直接在Java內存中分組或者排序。

因此,我們需要考慮在sql語句中使用order by 商品編號,先把數據排好順序,再查詢出數據,這樣就能將相同商品編號,倉庫不同的數據放到一起。

此外,還有一種情況需要考慮一下,通過配置的總記錄數將全部數據做了截取。

但如果最后一個商品編號在最后一頁中沒有查詢完,可能會導致導出的最后一個商品的數據不完整。

因此,我們需要在程序中處理一下,將最后一個商品刪除。

但加了order by關鍵字進行排序之后,如果查詢sql中join了很多張表,可能會導致查詢性能變差。

那么,該怎么辦呢?

總結

最后用兩張圖,總結一下excel異步導數據的流程。

如果是使用mq導數據:圖片

如果是使用job導數據:圖片

這兩種方式都可以,可以根據實際情況選擇使用。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Excel
    +關注

    關注

    4

    文章

    218

    瀏覽量

    55518
  • MySQL
    +關注

    關注

    1

    文章

    804

    瀏覽量

    26531
  • ui界面
    +關注

    關注

    0

    文章

    11

    瀏覽量

    1573
收藏 人收藏

    評論

    相關推薦

    百萬級別excel導出功能如何實現

    最近我做過一個MySQL 百萬級別 數據的 excel 導出功能,已經正常上線使用了。 這個功能挺有意思的,里面需要注意的細節還真不少,現在拿出來跟大家分享一下,希望對你會有所幫助。
    的頭像 發表于 09-25 11:38 ?1055次閱讀
    百萬級別<b class='flag-5'>excel</b><b class='flag-5'>導出</b><b class='flag-5'>功能</b>如何<b class='flag-5'>實現</b>

    表格導出Excel

    表格導出Excel,最近一個項目用到的,分給大家一起看看。
    發表于 03-10 10:31

    labview怎么實現把每次循環后的波形圖數據導出excel表格

    之前在論壇里也看到通過調用節點來實現波形數據導出excel,具體見https://bbs.elecfans.com/forum.php?mod=viewthread&tid=214922
    發表于 07-11 20:06

    列表存儲數據以及導出Excel表格中

    想做一個列表,顯示存儲的數據,然后還能導入到Excel表格里想要實現如下功能:1. 20個數據存成一行,一列代表一個變量。第一列為存儲時的時間。2017/03/15/15:20,時間顯示類似于這種
    發表于 03-15 09:56

    導出excel單元格屬性問題

    labview如何設置導出excel文件,讓其單元格屬性是文本格式的 默認是常規 這樣會導致導出的數據與原始數據不一致的情況 如0000變為0
    發表于 06-25 15:52

    .NETGRIDVIEW導出EXCEL怎么操作?

    請教一下大家.NETGRIDVIEW導出EXCEL怎么操作?
    發表于 11-04 10:08

    CAD表格怎么導出Excel?CAD表格導出

    軟件——浩辰CAD建筑軟件,操作方法很簡單的哦!浩辰CAD建筑軟件軟件提供了與 MS Office 和 WPS Office 之間導出表格文件的接口,把表格對象的內容輸出到 Word、Excel 或者
    發表于 06-05 14:10

    LabVIEW 將圖表數據導出Excel

    LabVIEW 將圖表數據導出Excel將圖形或圖表中的數據導出Excel。如何才能做到這一點?解答:在LabVIEW中,有內置的功能
    發表于 05-01 21:04

    關于labview波形圖表的導出數據至EXCEL的保存問題

    使用波形圖標調用節點或者直接右鍵保存數據至EXCEL可以實現功能,但是先生成圖表再保存,每次還得手動保存到指定位置。能不能直接指定一個保存的路徑,調用了以后直接保存完成。像波形圖標導出
    發表于 09-16 15:45

    基于Java反射機制的Excel文件導出實現_楊敏煜

    基于Java反射機制的Excel文件導出實現_楊敏煜
    發表于 03-18 09:46 ?1次下載

    組態王歷史數據導出EXCEL表格的方法

    怎么把組態王數據導出變成excel格式
    發表于 03-13 17:29 ?15次下載

    python導出excel格式的oracle數據報表講解

    python導出excel格式的oracle數據報表講解(通信電源技術期刊官網)-該文檔為python導出excel格式的oracle數據報表講解文檔,是一份還算不錯的參考文檔,感興趣
    發表于 09-28 13:10 ?7次下載
    python<b class='flag-5'>導出</b><b class='flag-5'>excel</b>格式的oracle數據報表講解

    如何寫一個公用工具來進行Excel的導入導出

    日常在做后臺系統的時候會很頻繁的遇到Excel導入導出的問題,正好這次在做一個后臺系統,就想著寫一個公用工具來進行Excel的導入導出
    的頭像 發表于 10-09 14:19 ?1473次閱讀

    記錄嵌入式Excel表格數據導出的構建過程

    最近有一個嵌入式Excel表格數據導出的需求:應用軟件運行于嵌入式Linux平臺上,在設備運行過程中,存儲了許多數據,這些數據想以表格的形式導出
    的頭像 發表于 10-27 11:14 ?1328次閱讀

    將數據從Arduino導出Excel工作表

    電子發燒友網站提供《將數據從Arduino導出Excel工作表.zip》資料免費下載
    發表于 12-07 09:19 ?1次下載
    將數據從Arduino<b class='flag-5'>導出</b>到<b class='flag-5'>Excel</b>工作表
    主站蜘蛛池模板: 国产精品99| 97超碰97资源在线观看| 亚洲黄色在线播放| 亚洲XXX午休国产熟女屁| 亚洲国产高清视频在线观看| 天天久久狠狠色综合| 香蕉eeww99国产精品| 亚洲乱色视频在线观看| 一个人看的www视频动漫版| 中国xxxxxxxxx孕交| 99精品网站| 高干紧射H后入| 好男人的视频在线观看| 快穿之诱受双性被灌满h| 人体内射精一区二区三区| 色妞色视频一区二区三区四区| 天天看学生视频| 亚洲欧洲日产国码中学| 99精品视频| 国产日韩亚洲精品视频| 久久女婷五月综合色啪| 日本特殊精油按摩| 亚洲中文字幕永久在线| 91chinesevideo| 在线不卡中文字幕| 34g污奶绵uk甩奶| 国产毛片A级久久久不卡精品| 老熟女毛茸茸浓毛| 雪恋电影完整版免费观看| 51精品少妇人妻AV一区二区| 国产九九九九九九九A片| 久久伊人中文字幕有码| 小SAO货水真多把你CAO烂| 99久久国产综合色| 九九热在线视频| 视频一区二区三区蜜桃麻豆| 伊人精品在线| 国产日韩精品一区二区三区在线| 秋霞在线观看视频一区二区三区| 一个人在线观看免费视频 | 国产又黄又硬又粗|