天天看點

jeesite poi大批量上傳檔案崩潰,OOM的解決方法

jeesite poi大批量上傳檔案崩潰,OOM的解決方法

這幾天用jeesite做個銀行績效考核,銀行資料過大,一個excel50多M,20多萬條資料,字段100多個個,如果用它自帶的poi,在循環插入資料庫的時候,會造出幾百萬的對象,瞬間填滿記憶體,而且循環沒完成時,還釋放不了對象。

當時也在想為什麼50M的資料就能填滿記憶體,但網上也沒個正式的說法,個人感覺認為,不能單純認為50Mexcel,傳上去就是50M,因為每條資料插入時會産生代碼片,每片都很大,那就是幾十萬的代碼片段塞入記憶體,瞬間就炸。

那來說說解決的辦法,首先你要下載下傳個阿裡巴巴的easyexcel,位址如下

https://github.com/alibaba/easyexcel

下載下傳後你導入eclipse,它是個maven工程導入,然後你先試驗下能不能用,github都有試驗教程,完成後你用eclipse的maven功能導出成jar包,這裡maven工程導出成jar包,百度有說明,理論上不倒成jar也能用,但我覺得導成jar包更友善。

我完成後是這樣的

jeesite poi大批量上傳檔案崩潰,OOM的解決方法

然後就可以使用啦,你在你要使用的地方加上如下代碼,

//注意你要是用的jeesite的話它自帶的poi傳入就是MultipartFile對象
//那你就可以用file.getInputStream()直接擷取流
InputStream inputStream = file.getInputStream();
DgkListener dgkListener = new DgkListener();
EasyExcelFactory.readBySax(inputStream, new Sheet(3, 1, ReadModel.class), dgkListener);
inputStream.close();
           

以上代碼中做添加到資料庫的操作是在DgkListener類中,我個人的如下:

//這裡我插入資料庫的操作是在service中完成,但這個類沒上交spring管理是以要先引入service
    private static DgckbaseigkBaseService dgckbaseigkBaseService = SpringContextHolder.getBean(DgckbaseigkBaseService.class);
    private List<ReadModel>  data = new ArrayList<ReadModel>();

    @Override
	public void invoke(Object object, AnalysisContext paramAnalysisContext) {
        if(data.size()<=1000){
			data.add((ReadModel) object);
        }else {
            doSomething();
            data = new ArrayList<ReadModel>();
            //這裡是我遇到的坑,原來下下來的沒用下面這段代碼,但這樣會造成資料少存入一行,莫名其妙
            //搞了半天,我在這裡加上如下代碼,就可以啦。也不知道寫這個人的人是怎麼用的,難道他們沒少?
            data.add((ReadModel) object);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        doSomething();
    }
    
    public void doSomething(){
    	//我直接每10001條傳入次service,做資料庫插入工作,完成後也是每10001次送出次事務
    	//事務送出在service最好添加,不然會很慢
    	dgckbaseigkBaseService.insertDb(data);
    }
           

總的來說就這樣了,一開始這個oom很難解決,網上很多文章教程也有,其實這個的原理跟poi官方的解決辦法,先把檔案上傳到伺服器形成cscv格式的文檔,然後程式再一行行的去讀這個檔案,讀完後删除。

easyexcel可能也是用這種方法,沒細看源碼。

說這麼多希望對你有所幫助。