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

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

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

瀏覽:156日期: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久久,三上悠亚国产精品一区二区三区
精品欧美日韩精品| 桃色一区二区| 亚洲国产一区二区在线观看 | 亚洲欧美日韩专区| 伊人久久亚洲热| 日韩午夜免费| 亚洲专区视频| 国产精品15p| 在线成人动漫av| 少妇精品在线| 欧美一区91| 精品国内亚洲2022精品成人| 欧美好骚综合网| 午夜免费一区| 午夜久久av| 激情综合五月| 好看不卡的中文字幕| 亚洲精品系列| 国产成人免费av一区二区午夜| 亚洲成人国产| 日本成人一区二区| 久久国内精品| 久久国产毛片| 男女精品网站| 欧美黄色一区| 欧美特黄一级大片| 亚洲五月综合| 成人污污视频| 99日韩精品| 久久99青青| 国产精品人人爽人人做我的可爱| 91成人福利| 日韩在线看片| 丝袜亚洲精品中文字幕一区| 超级白嫩亚洲国产第一| 欧美午夜精品一区二区三区电影| 欧美丰满日韩| 国产视频一区三区| 亚洲综合中文| 精品久久美女| 亚洲综合色婷婷在线观看| 久久不卡日韩美女| 九色精品91| 麻豆精品在线视频| 中文一区一区三区免费在线观 | 国精品一区二区| 国产日韩一区二区三区在线播放 | 91精品国产乱码久久久久久久| 欧美国产专区| 伊人影院久久| 91九色精品国产一区二区| 黄色aa久久| 一区二区精品伦理...| 美国三级日本三级久久99| 日韩欧美在线中字| 日韩中文字幕亚洲一区二区va在线 | 欧美日韩va| 欧美日韩一区二区三区视频播放| 免费在线看一区| 久久久国产精品入口麻豆| 久久午夜精品| 日韩网站中文字幕| 欧美国产另类| 日本中文字幕一区二区视频| 久久精品国产68国产精品亚洲| 美女免费视频一区| 一级成人国产| 亚洲专区视频| 麻豆精品在线播放| 国产精品va视频| 国产精品99一区二区| 玖玖玖国产精品| 麻豆mv在线观看| 久久国产精品免费一区二区三区| 久久久男人天堂| 国产精品xxxav免费视频| 免费观看在线色综合| 99视频精品全部免费在线视频| 精品国产网站| 国产黄色一区| 欧美精品三级在线| 亚州av一区| 丝袜美腿成人在线| 亚洲欧美一区在线| 99久久亚洲精品| 亚洲欧洲高清| 国产精品成人一区二区不卡| 欧美在线日韩| 日韩欧美四区| 亚洲最新av| 老牛国产精品一区的观看方式| 欧美日韩激情| 国产日本精品| 国产精品久久久久久久久久白浆| 国产亚洲电影| 国产精品主播在线观看| 欧美另类中文字幕| 91欧美极品| 国产精品亚洲人成在99www| 欧美日韩1区| 日韩成人精品一区二区三区 | 综合日韩av| 久久精品五月| 里番精品3d一二三区| 国产欧美一区二区精品久久久 | 六月婷婷综合| 日韩欧美少妇| 国产一区二区三区自拍| 99精品电影| 伊人久久亚洲美女图片| 国产精品免费看| 亚洲a成人v| 国产精品一区二区美女视频免费看 | 国产精品调教视频| 青青国产精品| 免费亚洲一区| 快播电影网址老女人久久| 久久青草久久| 蜜臀精品久久久久久蜜臀| 欧美日韩夜夜| 亚洲一区二区毛片| 蜜臀va亚洲va欧美va天堂| 亚洲资源网站| 色狠狠一区二区三区| 国产精品宾馆| 99精品美女| 日本一区二区中文字幕| 国产精品亚洲人成在99www| 国产精品成人a在线观看| 1024精品久久久久久久久| 日韩在线网址| а√天堂8资源中文在线| 影音国产精品| 国产欧美另类| 九九久久国产| 99国产精品久久久久久久成人热| 日本免费一区二区视频| а√天堂中文在线资源8| 三级精品视频| 亚洲一区二区三区中文字幕在线观看 | 国产精品自在| 91看片一区| 在线精品观看| 久久久久久一区二区| 麻豆成人在线| 丰满少妇一区| 久久av在线| 成人精品国产亚洲| 蜜臀久久99精品久久久久久9| 国产伦精品一区二区三区在线播放| 成人福利视频| 丝瓜av网站精品一区二区| 精品久久久网| 亚洲精品免费观看| 秋霞影院一区二区三区| 国产探花在线精品| 黄色亚洲大片免费在线观看| 国产麻豆一区二区三区| 欧美福利一区| 精品成av人一区二区三区| 黄色成人在线网址| 国产成人精品亚洲线观看| 综合一区在线| 日韩在线免费| 国产欧美高清| 久久福利影视| 国产精品成人一区二区不卡| 亚洲无线观看| 国产成人黄色| 国产午夜久久av| 亚洲资源网站| 99pao成人国产永久免费视频| 日韩av专区| 欧美三区不卡| 亚洲毛片视频| 亚洲激情黄色| 亚洲成人va| 久久亚洲道色| 日韩成人精品一区二区三区 | 久久精品国产免费| 日韩欧美三区| 亚洲综合电影一区二区三区| 中文字幕在线看片| 精品入口麻豆88视频| 日韩欧美久久| 中文字幕日本一区| 999在线观看精品免费不卡网站| 一本大道色婷婷在线| 美女久久久久久| 国产精品sss在线观看av| 亚洲香蕉视频| 亚洲成人精选| 久久网站免费观看| 中文字幕在线看片| 国产精品777777在线播放| 久久精品99国产精品| 日韩国产在线不卡视频| 日韩精品亚洲专区| 日韩一区二区三免费高清在线观看 | 久久精品资源|