在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

百萬(wàn)數(shù)據(jù)的導(dǎo)入導(dǎo)出解決方案

jf_ro2CN3Fa ? 來(lái)源: liu.kai ? 作者: liu.kai ? 2022-10-11 17:19 ? 次閱讀

前景

1 傳統(tǒng)POI的的版本優(yōu)缺點(diǎn)比較

2 使用方式哪種看情況

3 百萬(wàn)數(shù)據(jù)導(dǎo)入導(dǎo)出(正菜)

4 總結(jié)

前景

在項(xiàng)目開發(fā)中往往需要使用到數(shù)據(jù)的導(dǎo)入和導(dǎo)出,導(dǎo)入就是從Excel中導(dǎo)入到DB中,而導(dǎo)出就是從DB中查詢數(shù)據(jù)然后使用POI寫到Excel上。

寫本文的背景是因?yàn)樵诠ぷ髦杏龅搅舜髷?shù)據(jù)的導(dǎo)入和導(dǎo)出,問(wèn)題既然來(lái)了逃跑不如干掉它!!!

只要這一次解決了,后期遇到同樣的問(wèn)題就好解決了。

廢話不多說(shuō),開始擼起來(lái)!!!

1 傳統(tǒng)POI的的版本優(yōu)缺點(diǎn)比較

其實(shí)想到數(shù)據(jù)的導(dǎo)入導(dǎo)出,理所當(dāng)然的會(huì)想到apache的poi技術(shù),以及Excel的版本問(wèn)題。

既然要做導(dǎo)入導(dǎo)出,那么我們就先來(lái)大致看一下傳統(tǒng)poi技術(shù)的版本以及優(yōu)缺點(diǎn)對(duì)比吧!

首先我們知道POI中我們最熟悉的莫過(guò)于WorkBook這樣一個(gè)接口,我們的POI版本也在更新的同時(shí)對(duì)這個(gè)幾口的實(shí)現(xiàn)類做了更新:

HSSFWorkbook :

這個(gè)實(shí)現(xiàn)類是我們?cè)缙谑褂米疃嗟膶?duì)象,它可以操作Excel2003以前(包含2003)的所有Excel版本。在2003以前Excel的版本后綴還是.xls

XSSFWorkbook :

這個(gè)實(shí)現(xiàn)類現(xiàn)在在很多公司都可以發(fā)現(xiàn)還在使用,它是操作的Excel2003--Excel2007之間的版本,Excel的擴(kuò)展名是.xlsx

SXSSFWorkbook :

這個(gè)實(shí)現(xiàn)類是POI3.8之后的版本才有的,它可以操作Excel2007以后的所有版本Excel,擴(kuò)展名是.xlsx

大致知道了我們?cè)趯?dǎo)入導(dǎo)出操作的時(shí)候會(huì)用到這樣三個(gè)實(shí)現(xiàn)類以及他們可以操作的Excel版本和后綴之后,我們就要從優(yōu)缺點(diǎn)分析他們了

HSSFWorkbook

它是POI版本中最常用的方式,不過(guò):

它的缺點(diǎn)是 最多只能導(dǎo)出 65535行,也就是導(dǎo)出的數(shù)據(jù)函數(shù)超過(guò)這個(gè)數(shù)據(jù)就會(huì)報(bào)錯(cuò);

它的優(yōu)點(diǎn)是 不會(huì)報(bào)內(nèi)存溢出。(因?yàn)閿?shù)據(jù)量還不到7w所以內(nèi)存一般都?jí)蛴茫紫饶愕妹鞔_知道這種方式是將數(shù)據(jù)先讀取到內(nèi)存中,然后再操作)

XSSFWorkbook

優(yōu)點(diǎn):這種形式的出現(xiàn)是為了突破HSSFWorkbook的65535行局限,是為了針對(duì)Excel2007版本的1048576行,16384列,最多可以導(dǎo)出104w條數(shù)據(jù);

缺點(diǎn):伴隨的問(wèn)題來(lái)了,雖然導(dǎo)出數(shù)據(jù)行數(shù)增加了好多倍,但是隨之而來(lái)的內(nèi)存溢出問(wèn)題也成了噩夢(mèng)。因?yàn)槟闼鶆?chuàng)建的book,Sheet,row,cell等在寫入到Excel之前,都是存放在內(nèi)存中的(這還沒(méi)有算Excel的一些樣式格式等等),可想而知,內(nèi)存不溢出就有點(diǎn)不科學(xué)了!!!

SXSSFWorkbook

從POI 3.8版本開始,提供了一種基于XSSF的低內(nèi)存占用的SXSSF方式:

優(yōu)點(diǎn):

這種方式不會(huì)一般不會(huì)出現(xiàn)內(nèi)存溢出(它使用了硬盤來(lái)?yè)Q取內(nèi)存空間,

也就是當(dāng)內(nèi)存中數(shù)據(jù)達(dá)到一定程度這些數(shù)據(jù)會(huì)被持久化到硬盤中存儲(chǔ)起來(lái),而內(nèi)存中存的都是最新的數(shù)據(jù)),

并且支持大型Excel文件的創(chuàng)建(存儲(chǔ)百萬(wàn)條數(shù)據(jù)綽綽有余)。

缺點(diǎn):

既然一部分?jǐn)?shù)據(jù)持久化到了硬盤中,且不能被查看和訪問(wèn)那么就會(huì)導(dǎo)致,

在同一時(shí)間點(diǎn)我們只能訪問(wèn)一定數(shù)量的數(shù)據(jù),也就是內(nèi)存中存儲(chǔ)的數(shù)據(jù);

sheet.clone()方法將不再支持,還是因?yàn)槌志没脑?

不再支持對(duì)公式的求值,還是因?yàn)槌志没脑颍谟脖P中的數(shù)據(jù)沒(méi)法讀取到內(nèi)存中進(jìn)行計(jì)算;

在使用模板方式下載數(shù)據(jù)的時(shí)候,不能改動(dòng)表頭,還是因?yàn)槌志没膯?wèn)題,寫到了硬盤里就不能改變了;

2 使用方式哪種看情況

經(jīng)過(guò)了解也知道了這三種Workbook的優(yōu)點(diǎn)和缺點(diǎn),那么具體使用哪種方式還是需要看情況的:

我一般會(huì)根據(jù)這樣幾種情況做分析選擇:

1、當(dāng)我們經(jīng)常導(dǎo)入導(dǎo)出的數(shù)據(jù)不超過(guò)7w的情況下,可以使用 HSSFWorkbook 或者 XSSFWorkbook都行;

2、當(dāng)數(shù)據(jù)量查過(guò)7w并且導(dǎo)出的Excel中不牽扯對(duì)Excel的樣式,公式,格式等操作的情況下,推薦使用SXSSFWorkbook;

3、當(dāng)數(shù)據(jù)量查過(guò)7w,并且我們需要操做Excel中的表頭,樣式,公式等,這時(shí)候我們可以使用 XSSFWorkbook 配合進(jìn)行分批查詢,分批寫入Excel的方式來(lái)做;

3 百萬(wàn)數(shù)據(jù)導(dǎo)入導(dǎo)出(正菜)

鋪墊也做了不少,那么現(xiàn)在開始講講我在工作中遇到的超百萬(wàn)數(shù)據(jù)的導(dǎo)入導(dǎo)出解決方案:

想要解決問(wèn)題我們首先要明白自己遇到的問(wèn)題是什么?

1、 我遇到的數(shù)據(jù)量超級(jí)大,使用傳統(tǒng)的POI方式來(lái)完成導(dǎo)入導(dǎo)出很明顯會(huì)內(nèi)存溢出,并且效率會(huì)非常低;

2、 數(shù)據(jù)量大直接使用select * from tableName肯定不行,一下子查出來(lái)300w條數(shù)據(jù)肯定會(huì)很慢;

3、 300w 數(shù)據(jù)導(dǎo)出到Excel時(shí)肯定不能都寫在一個(gè)Sheet中,這樣效率會(huì)非常低;估計(jì)打開都得幾分鐘;

4、 300w數(shù)據(jù)導(dǎo)出到Excel中肯定不能一行一行的導(dǎo)出到Excel中。頻繁IO操作絕對(duì)不行;

5、 導(dǎo)入時(shí)300萬(wàn)數(shù)據(jù)存儲(chǔ)到DB如果循環(huán)一條條插入也肯定不行;

6、導(dǎo)入時(shí)300w數(shù)據(jù)如果使用Mybatis的批量插入肯定不行,因?yàn)镸ybatis的批量插入其實(shí)就是SQL的循環(huán);一樣很慢。

解決思路:

針對(duì)1 :

其實(shí)問(wèn)題所在就是內(nèi)存溢出,我們只要使用對(duì)上面介紹的POI方式即可,主要問(wèn)題就是原生的POI解決起來(lái)相當(dāng)麻煩。

經(jīng)過(guò)查閱資料翻看到阿里的一款POI封裝工具EasyExcel,上面問(wèn)題等到解決;

針對(duì)2:

不能一次性查詢出全部數(shù)據(jù),我們可以分批進(jìn)行查詢,只不過(guò)時(shí)多查詢幾次的問(wèn)題,況且市面上分頁(yè)插件很多。此問(wèn)題好解決。

針對(duì)3:

可以將300w條數(shù)據(jù)寫到不同的Sheet中,每一個(gè)Sheet寫一百萬(wàn)即可。

針對(duì)4:

不能一行一行的寫入到Excel上,我們可以將分批查詢的數(shù)據(jù)分批寫入到Excel中。

針對(duì)5:

導(dǎo)入到DB時(shí)我們可以將Excel中讀取的數(shù)據(jù)存儲(chǔ)到集合中,到了一定數(shù)量,直接批量插入到DB中。

針對(duì)6:

不能使用Mybatis的批量插入,我們可以使用JDBC的批量插入,配合事務(wù)來(lái)完成批量插入到DB。即 Excel讀取分批+JDBC分批插入+事務(wù)。

3.1 EasyExcel 簡(jiǎn)介

附上GitHub地址:https://github.com/alibaba/easyexcel

GitHub地址上教程和說(shuō)明很詳細(xì),并且附帶有讀和寫的demo代碼,這里對(duì)它的介紹我就不再詳細(xì)說(shuō)了。

至于EasyExcel底層怎么實(shí)現(xiàn)的這個(gè)還有待研究。

3.2 300w數(shù)據(jù)導(dǎo)出

EasyExcel完成300w數(shù)據(jù)的導(dǎo)出。技術(shù)難點(diǎn)已經(jīng)知道了,接下來(lái)就是針對(duì)這一難點(diǎn)提供自己的解決思路即可。

300w數(shù)據(jù)的導(dǎo)出解決思路:

首先在查詢數(shù)據(jù)庫(kù)層面,需要分批進(jìn)行查詢(我使用的是每次查詢20w)

每查詢一次結(jié)束,就使用EasyExcel工具將這些數(shù)據(jù)寫入一次;

當(dāng)一個(gè)Sheet寫滿了100w條數(shù)據(jù),開始將查詢的數(shù)據(jù)寫入到另一個(gè)Sheet中;

如此循環(huán)直到數(shù)據(jù)全部導(dǎo)出到Excel完畢。

注意:

1、我們需要計(jì)算Sheet個(gè)數(shù),以及循環(huán)寫入次數(shù)。特別是最后一個(gè)Sheet的寫入次數(shù)

因?yàn)槟悴恢雷詈笠粋€(gè)Sheet選喲寫入多少數(shù)據(jù),可能是100w,也可能是25w因?yàn)槲覀冞@里的300w只是模擬數(shù)據(jù),有可能導(dǎo)出的數(shù)據(jù)比300w多也可能少

2、我們需要計(jì)算寫入次數(shù),因?yàn)槲覀兪褂玫姆猪?yè)查詢,所以需要注意寫入的次數(shù)。

其實(shí)查詢數(shù)據(jù)庫(kù)多少次就是寫入多少次

//導(dǎo)出邏輯代碼
publicvoiddataExport300w(HttpServletResponseresponse){
{
OutputStreamoutputStream=null;
try{
longstartTime=System.currentTimeMillis();
System.out.println("導(dǎo)出開始時(shí)間:"+startTime);

outputStream=response.getOutputStream();
ExcelWriterwriter=newExcelWriter(outputStream,ExcelTypeEnum.XLSX);
StringfileName=newString(("excel100w").getBytes(),"UTF-8");

//title
Tabletable=newTable(1);
List>titles=newArrayList>();
titles.add(Arrays.asList("onlineseqid"));
titles.add(Arrays.asList("businessid"));
titles.add(Arrays.asList("becifno"));
titles.add(Arrays.asList("ivisresult"));
titles.add(Arrays.asList("createdby"));
titles.add(Arrays.asList("createddate"));
titles.add(Arrays.asList("updateby"));
titles.add(Arrays.asList("updateddate"));
titles.add(Arrays.asList("risklevel"));
table.setHead(titles);

//模擬統(tǒng)計(jì)查詢的數(shù)據(jù)數(shù)量這里模擬100w
intcount=3000001;
//記錄總數(shù):實(shí)際中需要根據(jù)查詢條件進(jìn)行統(tǒng)計(jì)即可
IntegertotalCount=actResultLogMapper.findActResultLogByCondations(count);
//每一個(gè)Sheet存放100w條數(shù)據(jù)
IntegersheetDataRows=ExcelConstants.PER_SHEET_ROW_COUNT;
//每次寫入的數(shù)據(jù)量20w
IntegerwriteDataRows=ExcelConstants.PER_WRITE_ROW_COUNT;
//計(jì)算需要的Sheet數(shù)量
IntegersheetNum=totalCount%sheetDataRows==0?(totalCount/sheetDataRows):(totalCount/sheetDataRows+1);
//計(jì)算一般情況下每一個(gè)Sheet需要寫入的次數(shù)(一般情況不包含最后一個(gè)sheet,因?yàn)樽詈笠粋€(gè)sheet不確定會(huì)寫入多少條數(shù)據(jù))
IntegeroneSheetWriteCount=sheetDataRows/writeDataRows;
//計(jì)算最后一個(gè)sheet需要寫入的次數(shù)
IntegerlastSheetWriteCount=totalCount%sheetDataRows==0?oneSheetWriteCount:(totalCount%sheetDataRows%writeDataRows==0?(totalCount/sheetDataRows/writeDataRows):(totalCount/sheetDataRows/writeDataRows+1));

//開始分批查詢分次寫入
//注意這次的循環(huán)就需要進(jìn)行嵌套循環(huán)了,外層循環(huán)是Sheet數(shù)目,內(nèi)層循環(huán)是寫入次數(shù)
List>dataList=newArrayList<>();
for(inti=0;ireslultList=actResultLogMapper.findByPage100w();
if(!CollectionUtils.isEmpty(reslultList)){
reslultList.forEach(item->{
dataList.add(Arrays.asList(item.getOnlineseqid(),item.getBusinessid(),item.getBecifno(),item.getIvisresult(),item.getCreatedby(),Calendar.getInstance().getTime().toString(),item.getUpdateby(),Calendar.getInstance().getTime().toString(),item.getRisklevel()));
});
}
//寫數(shù)據(jù)
writer.write0(dataList,sheet,table);
}
}

//下載EXCEL
response.setHeader("Content-Disposition","attachment;filename="+newString((fileName).getBytes("gb2312"),"ISO-8859-1")+".xlsx");
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
writer.finish();
outputStream.flush();
//導(dǎo)出時(shí)間結(jié)束
longendTime=System.currentTimeMillis();
System.out.println("導(dǎo)出結(jié)束時(shí)間:"+endTime+"ms");
System.out.println("導(dǎo)出所用時(shí)間:"+(endTime-startTime)/1000+"秒");
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}finally{
if(outputStream!=null){
try{
outputStream.close();
}catch(Exceptione){
e.printStackTrace();
}
}
}
}
}

3.2.1 測(cè)試機(jī)狀態(tài)

下面是測(cè)試機(jī)配置

ddebafb0-4925-11ed-a3b6-dac502259ad0.pngddf92186-4925-11ed-a3b6-dac502259ad0.pngde295298-4925-11ed-a3b6-dac502259ad0.pngde3a4648-4925-11ed-a3b6-dac502259ad0.png

3.2.2 使用數(shù)據(jù)庫(kù)版本

數(shù)據(jù)庫(kù)我使用的是Oracle19C在網(wǎng)上查閱其實(shí)在數(shù)據(jù)量不超過(guò)1億的情況下,Mysql和Oracle的性能其實(shí)相差不大,超過(guò)1億,Oracle的各方面優(yōu)勢(shì)才會(huì)明顯。

所以這里可以忽略使用數(shù)據(jù)庫(kù)對(duì)時(shí)間造成的影響,使用mysql一樣可以完成測(cè)試,不需要單獨(dú)安裝Oracle。

這次測(cè)試在查詢方面我使用的是rownum進(jìn)行的模擬查詢300w條數(shù)據(jù),這種查詢效率其實(shí)并不高,實(shí)際還有很多優(yōu)化空間來(lái)加快查詢速度,

如:明確查詢具體字段,不要用星號(hào),經(jīng)常查詢字段增加索引等盡可能提高查詢效率,用時(shí)可能會(huì)更短。


select*
fromACT_RESULT_LOG
whererownum3000001

--建表語(yǔ)句:可以參考一下
--Createtable
createtableACT_RESULT_LOG
(
onlineseqidVARCHAR2(32),
businessidVARCHAR2(32),
becifnoVARCHAR2(32),
ivisresultVARCHAR2(32),
createdbyVARCHAR2(32),
createddateDATE,
updatebyVARCHAR2(32),
updateddateDATE,
risklevelVARCHAR2(32)
)
tablespaceSTUDY_KAY
pctfree10
initrans1
maxtrans255
storage
(
initial64K
next1M
minextents1
maxextentsunlimited
);

3.2.3 測(cè)試結(jié)果

下面是300w數(shù)據(jù)從DB導(dǎo)出到Excel所用時(shí)間

從上面結(jié)果可以看出,300w的數(shù)據(jù)導(dǎo)出時(shí)間用時(shí)2分15秒,并且這是在不適用實(shí)體作為映射的情況下,如果使用實(shí)體映射不適用循環(huán)封裝的話速度會(huì)更快(當(dāng)然這也是在沒(méi)有設(shè)置表頭等其他表格樣式的情況下)

綜合來(lái)說(shuō)速度還算可以。

在網(wǎng)上查了很多資料有一個(gè)博主測(cè)試使用EasyExcel導(dǎo)出102w數(shù)據(jù)用時(shí)105秒。

看一下導(dǎo)出效果:文件還是挺大的163M

de54a3b2-4925-11ed-a3b6-dac502259ad0.pngde5f4330-4925-11ed-a3b6-dac502259ad0.png

3.2.4 導(dǎo)出小結(jié)

經(jīng)過(guò)測(cè)試EasyExcel還是挺快的,并且使用起來(lái)相當(dāng)方便,作者還專門提供了關(guān)流方法,不需要我們手動(dòng)去關(guān)流了,也避免了我們經(jīng)常忘記關(guān)流導(dǎo)致的一系列問(wèn)題。

導(dǎo)出測(cè)試就到這里,對(duì)于數(shù)據(jù)量小于300W的數(shù)據(jù)可以使用在一個(gè)Sheet中進(jìn)行導(dǎo)出。這里就不再演示。

3.3 300w數(shù)據(jù)導(dǎo)入

代碼不重要首先還是思路

300W數(shù)據(jù)的導(dǎo)入解決思路

1、首先是分批讀取讀取Excel中的300w數(shù)據(jù),這一點(diǎn)EasyExcel有自己的解決方案,我們可以參考Demo即可,只需要把它分批的參數(shù)3000調(diào)大即可。我是用的20w;(一會(huì)兒代碼一看就能明白)

2、其次就是往DB里插入,怎么去插入這20w條數(shù)據(jù),當(dāng)然不能一條一條的循環(huán),應(yīng)該批量插入這20w條數(shù)據(jù),同樣也不能使用Mybatis的批量插入語(yǔ),因?yàn)樾室驳汀?梢詤⒖枷旅骀溄印綧yabtis批量插入和JDBC批量插入性能對(duì)比】

3、使用JDBC+事務(wù)的批量操作將數(shù)據(jù)插入到數(shù)據(jù)庫(kù)。(分批讀取+JDBC分批插入+手動(dòng)事務(wù)控制)

3.3.1 數(shù)據(jù)庫(kù)數(shù)據(jù)(導(dǎo)入前)

如圖

de873a8e-4925-11ed-a3b6-dac502259ad0.png

3.3.2 核心業(yè)務(wù)代碼

//EasyExcel的讀取Excel數(shù)據(jù)的API
@Test
publicvoidimport2DBFromExcel10wTest(){
StringfileName="D:\StudyWorkspace\JavaWorkspace\java_project_workspace\idea_projects\SpringBootProjects\easyexcel\exportFile\excel300w.xlsx";
//記錄開始讀取Excel時(shí)間,也是導(dǎo)入程序開始時(shí)間
longstartReadTime=System.currentTimeMillis();
System.out.println("------開始讀取Excel的Sheet時(shí)間(包括導(dǎo)入數(shù)據(jù)過(guò)程):"+startReadTime+"ms------");
//讀取所有Sheet的數(shù)據(jù).每次讀完一個(gè)Sheet就會(huì)調(diào)用這個(gè)方法
EasyExcel.read(fileName,newEasyExceGeneralDatalListener(actResultLogService2)).doReadAll();
longendReadTime=System.currentTimeMillis();
System.out.println("------結(jié)束讀取Excel的Sheet時(shí)間(包括導(dǎo)入數(shù)據(jù)過(guò)程):"+endReadTime+"ms------");
}
//事件監(jiān)聽
publicclassEasyExceGeneralDatalListenerextendsAnalysisEventListener>{
/**
*處理業(yè)務(wù)邏輯的Service,也可以是Mapper
*/
privateActResultLogService2actResultLogService2;

/**
*用于存儲(chǔ)讀取的數(shù)據(jù)
*/
privateList>dataList=newArrayList>();

publicEasyExceGeneralDatalListener(){
}

publicEasyExceGeneralDatalListener(ActResultLogService2actResultLogService2){
this.actResultLogService2=actResultLogService2;
}

@Override
publicvoidinvoke(Mapdata,AnalysisContextcontext){
//數(shù)據(jù)add進(jìn)入集合
dataList.add(data);
//size是否為100000條:這里其實(shí)就是分批.當(dāng)數(shù)據(jù)等于10w的時(shí)候執(zhí)行一次插入
if(dataList.size()>=ExcelConstants.GENERAL_ONCE_SAVE_TO_DB_ROWS){
//存入數(shù)據(jù)庫(kù):數(shù)據(jù)小于1w條使用Mybatis的批量插入即可;
saveData();
//清理集合便于GC回收
dataList.clear();
}
}

/**
*保存數(shù)據(jù)到DB
*
*@param
*@MethodName:saveData
*@return:void
*/
privatevoidsaveData(){
actResultLogService2.import2DBFromExcel10w(dataList);
dataList.clear();
}

/**
*Excel中所有數(shù)據(jù)解析完畢會(huì)調(diào)用此方法
*
*@param:context
*@MethodName:doAfterAllAnalysed
*@return:void
*/
@Override
publicvoiddoAfterAllAnalysed(AnalysisContextcontext){
saveData();
dataList.clear();
}
}
//JDBC工具類
publicclassJDBCDruidUtils{
privatestaticDataSourcedataSource;

/*
創(chuàng)建數(shù)據(jù)Properties集合對(duì)象加載加載配置文件
*/
static{
Propertiespro=newProperties();
//加載數(shù)據(jù)庫(kù)連接池對(duì)象
try{
//獲取數(shù)據(jù)庫(kù)連接池對(duì)象
pro.load(JDBCDruidUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
dataSource=DruidDataSourceFactory.createDataSource(pro);
}catch(Exceptione){
e.printStackTrace();
}
}

/*
獲取連接
*/
publicstaticConnectiongetConnection()throwsSQLException{
returndataSource.getConnection();
}


/**
*關(guān)閉conn,和statement獨(dú)對(duì)象資源
*
*@paramconnection
*@paramstatement
*@MethodName:close
*@return:void
*/
publicstaticvoidclose(Connectionconnection,Statementstatement){
if(connection!=null){
try{
connection.close();
}catch(SQLExceptione){
e.printStackTrace();
}
}
if(statement!=null){
try{
statement.close();
}catch(SQLExceptione){
e.printStackTrace();
}
}
}

/**
*關(guān)閉conn,statement和resultset三個(gè)對(duì)象資源
*
*@paramconnection
*@paramstatement
*@paramresultSet
*@MethodName:close
*@return:void
*/
publicstaticvoidclose(Connectionconnection,Statementstatement,ResultSetresultSet){
close(connection,statement);
if(resultSet!=null){
try{
resultSet.close();
}catch(SQLExceptione){
e.printStackTrace();
}
}
}

/*
獲取連接池對(duì)象
*/
publicstaticDataSourcegetDataSource(){
returndataSource;
}

}
#druid.properties配置
driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbcthin:@localhost:1521:ORCL
username=mrkay
password=******
initialSize=10
maxActive=50
maxWait=60000
//Service中具體業(yè)務(wù)邏輯

/**
*測(cè)試用Excel導(dǎo)入超過(guò)10w條數(shù)據(jù),經(jīng)過(guò)測(cè)試發(fā)現(xiàn),使用Mybatis的批量插入速度非常慢,所以這里可以使用數(shù)據(jù)分批+JDBC分批插入+事務(wù)來(lái)繼續(xù)插入速度會(huì)非常快
*
*@param
*@MethodName:import2DBFromExcel10w
*@return:java.util.Map
*/
@Override
publicMapimport2DBFromExcel10w(List>dataList){
HashMapresult=newHashMap<>();
//結(jié)果集中數(shù)據(jù)為0時(shí),結(jié)束方法.進(jìn)行下一次調(diào)用
if(dataList.size()==0){
result.put("empty","0000");
returnresult;
}
//JDBC分批插入+事務(wù)操作完成對(duì)10w數(shù)據(jù)的插入
Connectionconn=null;
PreparedStatementps=null;
try{
longstartTime=System.currentTimeMillis();
System.out.println(dataList.size()+"條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:"+startTime+"ms");
conn=JDBCDruidUtils.getConnection();
//控制事務(wù):默認(rèn)不提交
conn.setAutoCommit(false);
Stringsql="insertintoACT_RESULT_LOG(onlineseqid,businessid,becifno,ivisresult,createdby,createddate,updateby,updateddate,risklevel)values";
sql+="(?,?,?,?,?,?,?,?,?)";
ps=conn.prepareStatement(sql);
//循環(huán)結(jié)果集:這里循環(huán)不支持"爛布袋"表達(dá)式
for(inti=0;iitem=dataList.get(i);
ps.setString(1,item.get(0));
ps.setString(2,item.get(1));
ps.setString(3,item.get(2));
ps.setString(4,item.get(3));
ps.setString(5,item.get(4));
ps.setTimestamp(6,newTimestamp(System.currentTimeMillis()));
ps.setString(7,item.get(6));
ps.setTimestamp(8,newTimestamp(System.currentTimeMillis()));
ps.setString(9,item.get(8));
//將一組參數(shù)添加到此PreparedStatement對(duì)象的批處理命令中。
ps.addBatch();
}
//執(zhí)行批處理
ps.executeBatch();
//手動(dòng)提交事務(wù)
conn.commit();
longendTime=System.currentTimeMillis();
System.out.println(dataList.size()+"條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:"+endTime+"ms");
System.out.println(dataList.size()+"條,導(dǎo)入用時(shí):"+(endTime-startTime)+"ms");
result.put("success","1111");
}catch(Exceptione){
result.put("exception","0000");
e.printStackTrace();
}finally{
//關(guān)連接
JDBCDruidUtils.close(conn,ps);
}
returnresult;
}

3.3.3 測(cè)試結(jié)果

下面是300w數(shù)據(jù)邊讀邊寫用時(shí)間:

大致計(jì)算一下:

從開始讀取到中間分批導(dǎo)入再到程序結(jié)束總共用時(shí): (1623127964725-1623127873630)/1000=91.095秒

300w數(shù)據(jù)正好是分15次插入綜合用時(shí):8209毫秒 也就是 8.209秒

計(jì)算可得300w數(shù)據(jù)讀取時(shí)間為:91.095-8.209=82.886秒

結(jié)果顯而易見:

EasyExcel分批讀取300W數(shù)據(jù)只用了 82.886秒

使用JDBC分批+事務(wù)操作插入300w條數(shù)據(jù)綜合只用時(shí) 8.209秒

------開始讀取Excel的Sheet時(shí)間(包括導(dǎo)入數(shù)據(jù)過(guò)程):1623127873630ms------
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127880632ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127881513ms
200000條,導(dǎo)入用時(shí):881ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127886945ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127887429ms
200000條,導(dǎo)入用時(shí):484ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127892894ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127893397ms
200000條,導(dǎo)入用時(shí):503ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127898607ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127899066ms
200000條,導(dǎo)入用時(shí):459ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127904379ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127904855ms
200000條,導(dǎo)入用時(shí):476ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127910495ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127910939ms
200000條,導(dǎo)入用時(shí):444ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127916271ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127916744ms
200000條,導(dǎo)入用時(shí):473ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127922465ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127922947ms
200000條,導(dǎo)入用時(shí):482ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127928260ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127928727ms
200000條,導(dǎo)入用時(shí):467ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127934374ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127934891ms
200000條,導(dǎo)入用時(shí):517ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127940189ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127940677ms
200000條,導(dǎo)入用時(shí):488ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127946402ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127946925ms
200000條,導(dǎo)入用時(shí):523ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127952158ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127952639ms
200000條,導(dǎo)入用時(shí):481ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127957880ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127958925ms
200000條,導(dǎo)入用時(shí):1045ms
200000條,開始導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127964239ms
200000條,結(jié)束導(dǎo)入到數(shù)據(jù)庫(kù)時(shí)間:1623127964725ms
200000條,導(dǎo)入用時(shí):486ms
------結(jié)束讀取Excel的Sheet時(shí)間(包括導(dǎo)入數(shù)據(jù)過(guò)程):1623127964725ms------

看一下數(shù)據(jù)庫(kù)的數(shù)據(jù)是不是真的存進(jìn)去了300w

可以看到數(shù)據(jù)比導(dǎo)入前多了300W,測(cè)試很成功

deb70b74-4925-11ed-a3b6-dac502259ad0.png

3.3.4 導(dǎo)入小結(jié)

具體我沒(méi)有看網(wǎng)上其他人的測(cè)試情況,這東西一般也很少有人愿意測(cè)試,不過(guò)這個(gè)速度對(duì)于我當(dāng)時(shí)解決公司大數(shù)據(jù)的導(dǎo)入和導(dǎo)出已經(jīng)足夠,當(dāng)然公司的業(yè)務(wù)邏輯很復(fù)雜,數(shù)據(jù)量也比較多,表的字段也比較多,導(dǎo)入和導(dǎo)出的速度會(huì)比現(xiàn)在測(cè)試的要慢一點(diǎn),但是也在人類能接受的范圍之內(nèi)。

4 總結(jié)

這次工作中遇到的問(wèn)題也給我留下了深刻印象,同時(shí)也是我職業(yè)生涯添彩的一筆。

最起碼簡(jiǎn)歷上可以寫上你處理過(guò)上百萬(wàn)條數(shù)據(jù)的導(dǎo)入導(dǎo)出。

最后說(shuō)一下公司之前怎么做的,公司之前做法是

限制了用戶的下載數(shù)量每次最多只能有四個(gè)人同時(shí)下載,并且控制每個(gè)用戶最大的導(dǎo)出數(shù)據(jù)最多只能是20w,與此同時(shí)他們也是使用的JDBC分批導(dǎo)入,但是并沒(méi)有手動(dòng)控制事務(wù)。

控制同時(shí)下載人數(shù)我可以理解,但是控制下載數(shù)據(jù)最多為20w就顯得有點(diǎn)雞肋了。

這也是我后期要解決的問(wèn)題。

好了到此結(jié)束,相信大神有比我做的更好的,對(duì)于EasyExcel內(nèi)部到底是怎么實(shí)現(xiàn)的還有待考究(有空我再研究研究)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)庫(kù)
    +關(guān)注

    關(guān)注

    7

    文章

    3874

    瀏覽量

    65418
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4868

    瀏覽量

    69897
  • POI
    POI
    +關(guān)注

    關(guān)注

    0

    文章

    8

    瀏覽量

    7072
  • 大數(shù)據(jù)
    +關(guān)注

    關(guān)注

    64

    文章

    8934

    瀏覽量

    138894

原文標(biāo)題:百萬(wàn)數(shù)據(jù)的導(dǎo)入導(dǎo)出解決方案

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    百萬(wàn)級(jí)別excel導(dǎo)出功能如何實(shí)現(xiàn)

    最近我做過(guò)一個(gè)MySQL 百萬(wàn)級(jí)別 數(shù)據(jù)的 excel 導(dǎo)出功能,已經(jīng)正常上線使用了。 這個(gè)功能挺有意思的,里面需要注意的細(xì)節(jié)還真不少,現(xiàn)在拿出來(lái)跟大家分享一下,希望對(duì)你會(huì)有所幫助。 原始需求:用戶
    的頭像 發(fā)表于 09-25 11:38 ?1215次閱讀
    <b class='flag-5'>百萬(wàn)</b>級(jí)別excel<b class='flag-5'>導(dǎo)出</b>功能如何實(shí)現(xiàn)

    不同格式設(shè)計(jì)數(shù)據(jù)導(dǎo)入導(dǎo)出

    支持的設(shè)計(jì)數(shù)據(jù)導(dǎo)入格式原理圖文件向下兼容Protel及Altium Designer先前版本原理圖和符號(hào)庫(kù)文件格式Protel 99SE數(shù)據(jù)包格式文件(*.DDB)P-CAD V16 或 V17
    發(fā)表于 07-11 15:30

    AD不同格式設(shè)計(jì)數(shù)據(jù)導(dǎo)入導(dǎo)出

    支持的設(shè)計(jì)數(shù)據(jù)導(dǎo)入格式原理圖文件向下兼容Protel及Altium Designer先前版本原理圖和符號(hào)庫(kù)文件格式Protel 99SE數(shù)據(jù)包格式文件(*.DDB)P-CAD V16 或 V17
    發(fā)表于 12-28 23:01

    Linux環(huán)境下oracle數(shù)據(jù)庫(kù)exp命令導(dǎo)出數(shù)據(jù)及imp命令導(dǎo)入數(shù)據(jù)

    一:以oracle用戶登錄Linux,使用命令:sqlplus / as sysdba進(jìn)入SQL命令模式;oracle數(shù)據(jù)庫(kù)exp命令導(dǎo)出數(shù)據(jù)及imp命令導(dǎo)入
    發(fā)表于 07-09 07:23

    INSTRUMENTS導(dǎo)出導(dǎo)入跟蹤數(shù)據(jù)

    INSTRUMENTS調(diào)試工具的使用(三十二) —— 高級(jí)任務(wù)之導(dǎo)出導(dǎo)入跟蹤數(shù)據(jù)(一)
    發(fā)表于 08-30 09:18

    Citect標(biāo)簽導(dǎo)入導(dǎo)出資料

    本章就Citect標(biāo)簽導(dǎo)入導(dǎo)出,其實(shí)包含變量標(biāo)簽、局部變量、趨勢(shì)標(biāo)簽、報(bào)警定義等都可以使用該方法來(lái)實(shí)現(xiàn)快速定義和修改
    發(fā)表于 05-10 17:25 ?0次下載
    Citect標(biāo)簽<b class='flag-5'>導(dǎo)入</b><b class='flag-5'>導(dǎo)出</b>資料

    PCB設(shè)計(jì):如何導(dǎo)入導(dǎo)出設(shè)計(jì)規(guī)則

    介紹如何在Altium Designer中導(dǎo)入導(dǎo)出設(shè)計(jì)規(guī)則,借鑒其他設(shè)計(jì)的優(yōu)秀合理的規(guī)則設(shè)置(寶貴的設(shè)計(jì)經(jīng)驗(yàn))為我所用,而不需要自己手動(dòng)創(chuàng)建。
    發(fā)表于 06-05 07:17 ?9857次閱讀
    PCB設(shè)計(jì):如何<b class='flag-5'>導(dǎo)入</b><b class='flag-5'>導(dǎo)出</b>設(shè)計(jì)規(guī)則

    XMC MCU 開發(fā)基礎(chǔ):DAVE3項(xiàng)目導(dǎo)入導(dǎo)出

    DAVE3 項(xiàng)目導(dǎo)入導(dǎo)出
    的頭像 發(fā)表于 07-11 02:12 ?4091次閱讀

    PCB技術(shù):Altium怎么安裝導(dǎo)入導(dǎo)出插件

    EDA軟件中Altium Designer的兼容性是最好的,在其他EDA平臺(tái)設(shè)計(jì)的原理圖、PCB等文件,有時(shí)候會(huì)統(tǒng)一到Altium Designer平臺(tái),或者將在Altium Designer平臺(tái)設(shè)計(jì)的文件導(dǎo)入其他平臺(tái),這種時(shí)候需要用到導(dǎo)入
    的頭像 發(fā)表于 10-14 10:36 ?6831次閱讀
    PCB技術(shù):Altium怎么安裝<b class='flag-5'>導(dǎo)入</b><b class='flag-5'>導(dǎo)出</b>插件

    MACSV數(shù)據(jù)庫(kù)導(dǎo)出導(dǎo)入的方法

    MACSV數(shù)據(jù)庫(kù)導(dǎo)出導(dǎo)入的方法(現(xiàn)代電源技術(shù)期末考試)-文檔為MACSV數(shù)據(jù)庫(kù)導(dǎo)出導(dǎo)入的方法
    發(fā)表于 09-17 15:41 ?2次下載
    MACSV<b class='flag-5'>數(shù)據(jù)</b>庫(kù)<b class='flag-5'>導(dǎo)出</b>、<b class='flag-5'>導(dǎo)入</b>的方法

    如何寫一個(gè)公用工具來(lái)進(jìn)行Excel的導(dǎo)入導(dǎo)出

    日常在做后臺(tái)系統(tǒng)的時(shí)候會(huì)很頻繁的遇到Excel導(dǎo)入導(dǎo)出的問(wèn)題,正好這次在做一個(gè)后臺(tái)系統(tǒng),就想著寫一個(gè)公用工具來(lái)進(jìn)行Excel的導(dǎo)入導(dǎo)出
    的頭像 發(fā)表于 10-09 14:19 ?1628次閱讀

    如何導(dǎo)入導(dǎo)出SCL源文件?

    如何導(dǎo)入導(dǎo)出SCL源文件?
    的頭像 發(fā)表于 01-16 10:41 ?2403次閱讀

    TIA Portal Openness導(dǎo)入/導(dǎo)出的基本原理

    可以導(dǎo)出某些組態(tài)數(shù)據(jù),然后在編輯之后再將數(shù)據(jù)重新導(dǎo)入同一項(xiàng)目或不同項(xiàng)目中。
    的頭像 發(fā)表于 06-21 11:48 ?4223次閱讀
    TIA Portal Openness<b class='flag-5'>導(dǎo)入</b>/<b class='flag-5'>導(dǎo)出</b>的基本原理

    數(shù)據(jù)庫(kù)的clob類型如何導(dǎo)入導(dǎo)出

    導(dǎo)入導(dǎo)出操作時(shí),可以使用不同的方法和工具來(lái)實(shí)現(xiàn),具體取決于數(shù)據(jù)庫(kù)的類型和版本。 一、導(dǎo)出CLOB類型數(shù)據(jù)
    的頭像 發(fā)表于 11-21 10:51 ?5487次閱讀

    適用于Oracle的SSIS數(shù)據(jù)流組件:提供快速導(dǎo)入導(dǎo)出功能

    使用SSIS 數(shù)據(jù)流組件,通過(guò)與關(guān)鍵數(shù)據(jù)庫(kù)和云服務(wù)的 Oracle 數(shù)據(jù)集成來(lái)改進(jìn)您的 ETL 流程,這些組件提供快捷和可靠的數(shù)據(jù)導(dǎo)入
    的頭像 發(fā)表于 01-15 10:51 ?441次閱讀
    適用于Oracle的SSIS<b class='flag-5'>數(shù)據(jù)</b>流組件:提供快速<b class='flag-5'>導(dǎo)入</b>及<b class='flag-5'>導(dǎo)出</b>功能
    主站蜘蛛池模板: 免费毛片软件 | free 欧美| 国产福利在线观看一区二区 | 欧美爆插| 久久精品国产99国产精品免费看 | 黄色在线看网站 | 亚洲最大的成人网 | 成年女人免费看一级人体片 | 啪啪调教所29下拉式免费阅读 | 婷婷丁香综合 | www.亚洲欧美 | 国外一级毛片 | 午夜爽爽性刺激一区二区视频 | 黄视频网站入口 | 最新欧美伦理网 | 狠狠色丁香婷婷综合橹不卡 | 亚洲色图综合 | 色丁香在线 | 天天弄天天模 | 亚洲播播 | 天天久久 | 性满足久久久久久久久 | 色男人网 | 韩国理论三级在线观看视频 | 亚洲地址一地址二地址三 | 特黄特黄特色大片免费观看 | 美女性爽视频国产免费 | 制服丝袜中文字幕第一页 | 性生大片一级毛片免费观看 | 亚洲精品视频免费 | 四虎国产精品免费久久影院 | 天堂网在线.www天堂在线 | 黄色一级毛片看一级毛片 | 午夜视频在线观看免费观看在线观看 | 亚洲免费成人在线 | 午夜免费视频观看 | 男人的午夜天堂 | 日本在线不卡免费 | 特黄特a级特别特级特毛片 特黄特色大片免费播放路01 | 天天好比 | 久久久噜噜噜久久网 |