最近在做一個需求是導出較大的excel,本文是記錄我在做需求過程中遇到的幾個問題和解題方法,給大家分享一下,一來可以幫助同樣遇到問題的朋友,二呢,各位大神也許有更好的方法可以指點小弟一下,讓我順便學習一下。
背景::工頭:“小鍾啊,xx界面加個導出excel功能03以后的格式,需要能支持到excel的最大行,同時需要5個並發就行”
我:“收到,但是數據大的時候速度可能比較慢。”
工頭:“你先做后續客戶反饋了在給他加進度條。”
Npoi神器介紹:SXSSFWorkbook 專門用來導出大數據用,他會把數據先寫入C盤的臨時目錄;不會所有 都留在內存里;更詳細介紹請百度或者參考(
http://poi.apache.org/components/spreadsheet/how-to.html#sxssf)
有了這層基礎開始劈里啪啦一段操作寫代碼;(以下代碼非生產代碼只是我為了帖子寫重現問題的測試代碼)
首先開個線程模擬並發

編寫導出方法:記錄時間、創建SXSSFWorkbook 代碼如圖:

啟動運行;

好!第一口鍋已造好,看這個提示,前面說了SXSSFWorkbook 是會先把緩存數據寫入Windows臨時文件里頭的,這個目錄正好是Windows的臨時文件夾雖然是個錯誤但是驗證了剛剛的說法;至於這個錯誤看提示 我們有個大膽的想法是文件占用問題,應該是創建文件的時候文件已經存在了,這樣我們把npoi的dll打開來看看,通過看源碼和各種f12我們看到了這么一段代碼

這里看到用來隨機數,而我們知道net的隨機數在極短的時間內生成是不可靠的(詳見百度或者:
https://docs.microsoft.com/zh-cn/dotnet/api/system.random.-ctor?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev16.query%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk(System.Random.%2523ctor);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.0);k(DevLang-csharp)%26rd%3Dtrue&view=netframework-4.8)也就是說生成一樣的文件名,然后我們在通過 github里可以看到

早在年初NPOI就對這個問題做了更改就換成guid了,隨后我來到了nuget

nuget最新版 是去年12月份發布,並沒有包含上面的更改;
所以呢 要么github下載最新版編譯要么自己解決,想了想如果換版本的話以前的功能可能會影響到所以,我們就在外面加一把小鎖吧!如圖


這樣呢我們在試試!

很好 不會在出現文件占用問題了;好繼續導出!
既然是都先寫入緩存文件是不是占用的內存就很小了 來看看

2G多。。。什么情況,還在漲

3G。。。這明顯不符合工頭的需求了,然后終於它炸了

第一念頭是為啥我該怎么辦,設置GC的回收模式?手動多GC?還是要把代碼給拿下來看看,看看這么大內存哪里沒釋放文件?冷靜、冷靜、想想,既然是內存爆了 那么正確流程應該是抓取看看是什么吃的內存得出結果再去改東西,

發現了啥是不是很熟悉的東西? 狀態管理、包裝類,想到了啥 EF的“模型跟蹤”這個功能占用的內存最大了。那就去掉吧 加上這么一句 意思是無跟蹤查詢 ,修改實例后SaveChanges不對對它生效;

(AsNoTracking 更詳情理解介紹請百度在加上msdn:
https://docs.microsoft.com/zh-cn/ef/ef6/querying/no-tracking?redirectedfrom=MSDN )
現在在繼續導出看看:

內存是吃的不大了,

可以看出臨時文件還是很大的,這還沒導完呢,所以做的時候 盡量要保證下硬盤的空間!
等待。。。
總結:
1.導出大數據用SXSSFWorkbook
2.構建SXSSFWorkbook 時候lock或者自己編譯最新版本
3.我們做導出時,ef查詢數據后記得加AsNoTracking 關閉綁定跟蹤。(以后日常開發中如果只需要查詢的也可以這樣做)
4.SXSSFWorkbook 導出大數據 臨時文件夾所在的硬盤不能太小 因為會生成大於excel本身的緩存文件!



最后導出完畢

用時:

