日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

使用Springboot+poi上傳并處理百萬級數據EXCEL

瀏覽:159日期:2022-06-16 14:23:09

1 Excel上傳

針對Excel的上傳,采用的是比較常規的方法,其實和文件上傳是相同的。具體源碼如下:

@PostMapping(value = '', consumes = 'multipart/*', headers = 'content-type=multipart/form-data') public Map<String, Object> addBlacklist( @RequestParam('file') MultipartFile multipartFile, HttpServletRequest request ) { //判斷上傳內容是否符合要求 String fileName = multipartFile.getOriginalFilename(); if (!fileName.matches('^.+.(?i)(xls)$') && !fileName.matches('^.+.(?i)(xlsx)$')) { return returnError(0,'上傳的文件格式不正確'); } String file = saveFile(multipartFile, request); int result = 0; try { result = blacklistServcice.addBlackLists(file); } catch (Exception e) { e.printStackTrace(); } return returnData(result); } private String saveFile(MultipartFile multipartFile, HttpServletRequest request) { String path; String fileName = multipartFile.getOriginalFilename(); // 判斷文件類型 String realPath = request.getSession().getServletContext().getRealPath('/'); String trueFileName = fileName; // 設置存放Excel文件的路徑 path = realPath + trueFileName; File file = new File(path); if (file.exists() && file.isFile()) { file.delete(); } try { multipartFile.transferTo(new File(path)); } catch (IOException e) { e.printStackTrace(); } return path; }

上面的源碼我們可以看見有一個saveFile方法,這個方法是將文件存在服務器本地,這樣方便后續文件內容的讀取,用不著一次讀取所有的內容從而導致消耗大量的內存。當然這里大家如果有更好的方法希望能留言告知哈。

2 Excel處理工具源碼

import org.apache.poi.openxml4j.opc.OPCPackage;import org.apache.poi.xssf.eventusermodel.XSSFReader;import org.apache.poi.xssf.model.SharedStringsTable;import org.apache.poi.xssf.usermodel.XSSFRichTextString;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import org.xml.sax.helpers.DefaultHandler;import org.xml.sax.helpers.XMLReaderFactory; import java.io.InputStream;import java.sql.SQLException;import java.util.*; /** * XSSF and SAX (Event API) */public abstract class XxlsAbstract extends DefaultHandler { private SharedStringsTable sst; private String lastContents; private int sheetIndex = -1; private List<String> rowlist = new ArrayList<>(); public List<Map<String, Object>> dataMap = new LinkedList<>(); //即將進行批量插入的數據 public int willSaveAmount; //將要插入的數據量 public int totalSavedAmount; //總共插入了多少數據 private int curRow = 0; //當前行 private int curCol = 0; //當前列索引 private int preCol = 0; //上一列列索引 private int titleRow = 0; //標題行,一般情況下為0 public int rowsize = 0; //列數 //excel記錄行操作方法,以sheet索引,行索引和行元素列表為參數,對sheet的一行元素進行操作,元素為String類型 public abstract void optRows(int sheetIndex, int curRow, List<String> rowlist) throws SQLException; //只遍歷一個sheet,其中sheetId為要遍歷的sheet索引,從1開始,1-3 /** * @param filename * @param sheetId sheetId為要遍歷的sheet索引,從1開始,1-3 * @throws Exception */ public void processOneSheet(String filename, int sheetId) throws Exception { OPCPackage pkg = OPCPackage.open(filename); XSSFReader r = new XSSFReader(pkg); SharedStringsTable sst = r.getSharedStringsTable(); XMLReader parser = fetchSheetParser(sst); // rId2 found by processing the Workbook // 根據 rId# 或 rSheet# 查找sheet InputStream sheet2 = r.getSheet('rId' + sheetId); sheetIndex++; InputSource sheetSource = new InputSource(sheet2); parser.parse(sheetSource); sheet2.close(); } public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException { XMLReader parser = XMLReaderFactory.createXMLReader(); this.sst = sst; parser.setContentHandler(this); return parser; } public void endElement(String uri, String localName, String name) { // 根據SST的索引值的到單元格的真正要存儲的字符串 try { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)) .toString(); } catch (Exception e) { } // v => 單元格的值,如果單元格是字符串則v標簽的值為該字符串在SST中的索引 // 將單元格內容加入rowlist中,在這之前先去掉字符串前后的空白符 if (name.equals('v')) { String value = lastContents.trim(); value = value.equals('') ? ' ' : value; int cols = curCol - preCol; if (cols > 1) {for (int i = 0; i < cols - 1; i++) { rowlist.add(preCol, '');} } preCol = curCol; rowlist.add(curCol - 1, value); } else { //如果標簽名稱為 row ,這說明已到行尾,調用 optRows() 方法 if (name.equals('row')) {int tmpCols = rowlist.size();if (curRow > this.titleRow && tmpCols < this.rowsize) { for (int i = 0; i < this.rowsize - tmpCols; i++) { rowlist.add(rowlist.size(), ''); }}try { optRows(sheetIndex, curRow, rowlist);} catch (SQLException e) { e.printStackTrace();}if (curRow == this.titleRow) { this.rowsize = rowlist.size();}rowlist.clear();curRow++;curCol = 0;preCol = 0; } } }}

3 解析成功后的數據處理

首先我們將源碼展示出來,然后再具體說明

public int addBlackLists(String file) throws ExecutionException, InterruptedException { ArrayList<Future<Integer>> resultList = new ArrayList<>(); XxlsAbstract xxlsAbstract = new XxlsAbstract() { //針對數據的具體處理 @Override public void optRows(int sheetIndex, int curRow, List<String> rowlist) { /** * 判斷即將插入的數據是否已經到達8000,如果到達8000, * 進行數據插入 */if (this.willSaveAmount == 5000) { //插入數據 List<Map<String, Object>> list = new LinkedList<>(this.dataMap); Callable<Integer> callable = () -> { int count = blacklistMasterDao.addBlackLists(list); blacklistRecordMasterDao.addBlackListRecords(list); return count; }; this.willSaveAmount = 0; this.dataMap = new LinkedList<>(); Future<Integer> future = executor.submit(callable); resultList.add(future);} //匯總數據Map<String, Object> map = new HashMap<>();map.put('uid', rowlist.get(0));map.put('createTime', rowlist.get(1));map.put('regGame', rowlist.get(2)); map.put('banGame', rowlist.get(2));this.dataMap.add(map);this.willSaveAmount++;this.totalSavedAmount++; } }; try { xxlsAbstract.processOneSheet(file, 1); } catch (Exception e) { e.printStackTrace(); } //針對沒有存入的數據進行處理 if(xxlsAbstract.willSaveAmount != 0){ List<Map<String, Object>> list = new LinkedList<>(xxlsAbstract.dataMap); Callable<Integer> callable = () -> {int count = blacklistMasterDao.addBlackLists(list);blacklistRecordMasterDao.addBlackListRecords(list);return count; }; Future<Integer> future = executor.submit(callable); resultList.add(future); } executor.shutdown(); int total = 0; for (Future<Integer> future : resultList) { while (true) {if (future.isDone() && !future.isCancelled()) { int sum = future.get(); total += sum; break;} else { Thread.sleep(100);} } } return total; }

針對上面的源碼,我們可以發現,我們需要將讀取到的EXCEL數據插入到數據庫中,這里為了減小數據庫的IO和提高插入的效率,我們采用5000一批的批量插入(注意:如果數據量過大會導致組成的SQL語句無法執行)。

這里需要獲取到一個最終執行成功的插入結果,并且插入執行很慢。所有采用了Java多線程的Future模式,采用異步的方式最終來獲取J執行結果。

通過上面的實現,樓主測試得到最終一百萬條數據需要四分鐘左右的時間就可以搞定。如果大家有更好的方法,歡迎留言。

補充知識:Java API SXSSFWorkbook導出Excel大批量數據(百萬級)解決導出超時

之前使用簡單的HSSFWorkbook,導出的數據不能超過

使用Springboot+poi上傳并處理百萬級數據EXCEL

后來改成SXSSFWorkbook之后可以導出更多,但是

而且我之前的代碼是一次性查出所有數據,幾十萬條,直接就超時了。

之前的代碼是一次性查出所有的結果,list里面存了幾十萬條數據。因為功能設計的問題,我這一個接口要同時處理三個功能:

使用Springboot+poi上傳并處理百萬級數據EXCEL

再加上查詢SQL的效率問題,導致請求超時。

現在為了做到處更大量的數據只能選擇優化。優化查詢的sql這里就不講了,只講導出功能的優化。

其實就是分批次處理查詢結果:

使用Springboot+poi上傳并處理百萬級數據EXCEL

這樣做的好處是查詢速度變快,封裝速度也變快,整體速度變快就不會出現超時,而且,每次分頁查出的結果放到list中不會出現占用JVM內存過大的情況。避免出現內存溢出導致系統崩潰。

再次優化:

上面這樣做雖然可以導出,但是代碼看起來不美觀:

使用Springboot+poi上傳并處理百萬級數據EXCEL

這樣看起來就簡潔很多了。

經驗證,查詢加封裝EXCEL7000條數據處理只需要1秒

使用Springboot+poi上傳并處理百萬級數據EXCEL

使用Springboot+poi上傳并處理百萬級數據EXCEL

使用Springboot+poi上傳并處理百萬級數據EXCEL

以上這篇使用Springboot+poi上傳并處理百萬級數據EXCEL就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: excel
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩视频一区| 91伊人久久| 日韩欧美一区二区三区免费观看| 欧美精品不卡| 国产乱码精品一区二区三区亚洲人| 国产精品亚洲二区| 日韩综合在线| 日韩欧美激情电影| 亚洲精品动态| 久久久久亚洲精品中文字幕| 久久久久国产精品一区二区| 亚洲欧洲一区二区天堂久久| 蜜桃一区二区三区在线| 欧美精品观看| 欧洲一区二区三区精品| 国产精品88久久久久久| 亚洲免费一区三区| 国产成人免费精品| 亚洲尤物在线| 日韩精品欧美大片| 精品一区av| 香蕉成人久久| 麻豆视频在线观看免费网站黄| 亚洲大全视频| 日本午夜精品久久久| 日韩成人综合| 国产精品成人自拍| 亚洲主播在线| 婷婷亚洲综合| 91亚洲国产| 欧美交a欧美精品喷水| 国产亚洲一级| 91精品91| 在线午夜精品| 日韩精品一区二区三区免费观看| 日本va欧美va精品发布| 99re国产精品| 国产毛片精品| 黑丝美女一区二区| 91精品在线观看国产| 国产成人精品一区二区免费看京 | 91青青国产在线观看精品| 五月激激激综合网色播| 国产精品88久久久久久| 中文字幕一区二区av| 国产成人精品亚洲线观看| 深夜福利一区| 女主播福利一区| 另类小说一区二区三区| 日韩和欧美的一区| 国产精品久久久久蜜臀| 国产精品调教| 欧美日韩网址| 日韩国产欧美在线视频| 美女精品在线| 亚洲欧洲另类| 99视频一区| 最新国产拍偷乱拍精品| 久久一区二区三区喷水| 成人在线丰满少妇av| 久久午夜影院| 国产+成+人+亚洲欧洲在线| 国产精品激情| 日韩高清不卡在线| 日本午夜免费一区二区| 日韩高清不卡一区二区| 日韩极品在线观看| 国产精品片aa在线观看| 国产精品日本一区二区不卡视频| 久久精品超碰| 国语精品一区| av日韩中文| 欧美高清一区| 日韩中文字幕| 国产精品视频一区二区三区| 精品亚洲二区| 色爱av综合网| 久久一二三区| 日韩精品三级| 精品亚洲精品| 黄色亚洲精品| 欧美日韩99| 精品中文字幕一区二区三区四区| 精品国产中文字幕第一页| 国产一区二区三区天码| 久久精品国产成人一区二区三区| 久久国产精品色av免费看| 国产精品videossex久久发布| 日韩和欧美一区二区| 欧美性www| 精品国产乱码久久久| 国产综合婷婷| 色综合视频一区二区三区日韩| 日韩区欧美区| 精品丝袜在线| 日本视频在线一区| 亚洲天堂免费电影| 奇米狠狠一区二区三区| 日韩激情一区| 日韩精品久久理论片| 91精品一区二区三区综合在线爱 | 91成人精品视频| 国产精品久久久久久模特| 国产主播一区| 精品理论电影在线| 中文字幕av一区二区三区人| 鲁大师精品99久久久| 亚洲欧美网站| 日韩欧美午夜| 奇米狠狠一区二区三区| 国产综合激情| 超碰成人av| 日韩二区三区四区| 黄色成人91| 欧美网站在线| 精品免费av| 国产美女亚洲精品7777| 欧美日韩免费观看一区=区三区| 卡一卡二国产精品| 日韩精品高清不卡| 亚洲一区二区网站| 国产白浆在线免费观看| 麻豆精品国产91久久久久久| 日韩午夜视频在线| 综合欧美精品| 日本午夜精品久久久| 日本天堂一区| 久久爱www成人| 老司机精品视频在线播放| 国产精品综合色区在线观看| 中文字幕一区日韩精品| 婷婷亚洲精品| 国产欧美综合一区二区三区| 日韩激情一区二区| 国产亚洲人成a在线v网站| 日韩精品国产欧美| 国产欧美啪啪| 精品国产一区二区三区性色av| 久久精品国产999大香线蕉| 欧美激情aⅴ一区二区三区 | 麻豆中文一区二区| 精品成人18| 国产成年精品| 日韩理论片av| 亚洲欧美日韩高清在线| 蜜臀av性久久久久蜜臀aⅴ流畅| 欧美亚洲免费| 色乱码一区二区三区网站| 中文在线а√在线8| 欧美日韩在线二区| 国产一区导航| 欧美视频二区| 日韩天堂在线| 亚洲一区av| 国产美女久久| 日韩一级精品| 欧美一区自拍| 日韩欧美精品一区| 久久成人亚洲| 麻豆久久一区二区| 国产亚洲毛片| 视频在线不卡免费观看| 亚洲免费激情| 麻豆国产欧美一区二区三区 | 日韩精品欧美| 久久国产人妖系列| 亚洲成人二区| 国产精品久久久亚洲一区| japanese国产精品| 久草精品视频| 日韩av中文字幕一区二区三区| 极品裸体白嫩激情啪啪国产精品| 亚洲欧洲免费| 欧美日韩国产免费观看视频| 精品国产一区二区三区av片| 免费在线观看一区二区三区| 成人台湾亚洲精品一区二区| 亚洲天堂av资源在线观看| 成人精品天堂一区二区三区| 国产精品探花在线观看| 六月丁香综合| 精品一区在线| 久久精品国语| 美女av在线免费看| 成人台湾亚洲精品一区二区| 久久国内精品| 亚洲精品第一| 亚洲视频二区| 欧美一级精品| 99久久久久| 久久免费高清| 精品在线91| 免费国产亚洲视频| 亚洲免费福利一区| 午夜一区在线| 亚洲欧美专区| 青草国产精品久久久久久| 亚洲欧美久久精品| 欧美视频久久| 久久影院资源站|