您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“用java怎么快速從系統(tǒng)報(bào)表頁面導(dǎo)出20w條數(shù)據(jù)”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
先不談技術(shù),先看效果,(完整案例代碼文末提供)
數(shù)據(jù)庫為mysql(理論上此套方案支持任何結(jié)構(gòu)化數(shù)據(jù)庫),準(zhǔn)備一張測試表t_person
。表結(jié)構(gòu)如下:
CREATE TABLE `t_person` ( `id` bigint(20) NOT NULL auto_increment, `name` varchar(20) default NULL, `age` int(11) default NULL, `address` varchar(50) default NULL, `mobile` varchar(20) default NULL, `email` varchar(50) default NULL, `company` varchar(50) default NULL, `title` varchar(50) default NULL, `create_time` datetime default NULL, PRIMARY KEY (`id`) );
一共9個(gè)字段。我們先創(chuàng)建測試數(shù)據(jù)。
案例代碼提供了一個(gè)簡單的頁面,點(diǎn)以下按鈕一次性可以創(chuàng)建5w條測試數(shù)據(jù):
這里我連續(xù)點(diǎn)了4下,很快就生成了20w條數(shù)據(jù),這里為了展示下數(shù)據(jù)的大致樣子,我直接跳轉(zhuǎn)到了最后一頁
然后點(diǎn)開下載大容量文件
,點(diǎn)擊執(zhí)行執(zhí)行按鈕,開始下載t_person
這張表里的全部數(shù)據(jù)
點(diǎn)擊執(zhí)行按鈕之后,點(diǎn)下方刷新按鈕,可以看到一條異步下載記錄,狀態(tài)是P
,表示pending
狀態(tài),不停刷新刷新按鈕,大概幾秒后,這一條記錄就變成S
狀態(tài)了,表示Success
然后你就可以下載到本地,文件大小大概31M左右
看到這里,很多童鞋要疑惑了,這下載下來是csv?csv其實(shí)是文本文件,用excel打開會(huì)丟失格式和精度。這解決不了問題啊,我們要excel格式啊??!
其實(shí)稍微會(huì)一點(diǎn)excel技巧的童鞋,可以利用excel導(dǎo)入數(shù)據(jù)這個(gè)功能,數(shù)據(jù)->導(dǎo)入數(shù)據(jù),根據(jù)提示一步步,當(dāng)中只要選擇逗號分隔就可以了,關(guān)鍵列可以定義格式,10秒就能完成數(shù)據(jù)的導(dǎo)入
你只要告訴運(yùn)營小姐姐,根據(jù)這個(gè)步驟來完成excel的導(dǎo)入就可以了。而且下載過的文件,還可以反復(fù)下。
是不是從本質(zhì)上解決了下載大容量數(shù)據(jù)集的問題?
學(xué)弟聽到這里,很興奮的說,這套方案能解決我這里的痛點(diǎn)??旌臀艺f說原理。
其實(shí)這套方案核心很簡單,只源于一個(gè)知識點(diǎn),活用JdbcTemplate
的這個(gè)接口:
@Override public void query(String sql, @Nullable Object[] args, RowCallbackHandler rch) throws DataAccessException { query(sql, newArgPreparedStatementSetter(args), rch); }
sql就是select * from t_person
,RowCallbackHandler
這個(gè)回調(diào)接口是指每一條數(shù)據(jù)遍歷后要執(zhí)行的回調(diào)函數(shù)?,F(xiàn)在貼出我自己的RowCallbackHandler
的實(shí)現(xiàn)
private class CsvRowCallbackHandler implements RowCallbackHandler{ private PrintWriter pw; public CsvRowCallbackHandler(PrintWriter pw){ this.pw = pw; } public void processRow(ResultSet rs) throws SQLException { if (rs.isFirst()){ rs.setFetchSize(500); for (int i = 0; i < rs.getMetaData().getColumnCount(); i++){ if (i == rs.getMetaData().getColumnCount() - 1){ this.writeToFile(pw, rs.getMetaData().getColumnName(i+1), true); }else{ this.writeToFile(pw, rs.getMetaData().getColumnName(i+1), false); } } }else{ for (int i = 0; i < rs.getMetaData().getColumnCount(); i++){ if (i == rs.getMetaData().getColumnCount() - 1){ this.writeToFile(pw, rs.getObject(i+1), true); }else{ this.writeToFile(pw, rs.getObject(i+1), false); } } } pw.println(); } private void writeToFile(PrintWriter pw, Object valueObj, boolean isLineEnd){ ... } }
這個(gè)CsvRowCallbackHandler
做的事就是每次從數(shù)據(jù)庫取出500條,然后寫入服務(wù)器上的本地文件中,這樣,無論你這條sql查出來是20w條還是100w條,內(nèi)存理論上只占用500條數(shù)據(jù)的存儲空間。等文件寫完了,我們要做的,只是從服務(wù)器把這個(gè)生成好的文件download到本地就可以了。
因?yàn)閮?nèi)存中不斷刷新的只有500條數(shù)據(jù)的容量,所以,即便多線程下載的環(huán)境下。內(nèi)存也不會(huì)因此而溢出。這樣,完美解決了多人下載的場景。
當(dāng)然,太多并行下載雖然不會(huì)對內(nèi)存造成溢出,但是會(huì)大量占用IO資源。為此,我們還是要控制下多線程并行的數(shù)量,可以用線程池來提交作業(yè)
ExecutorService threadPool = Executors.newFixedThreadPool(5); threadPool.submit(new Thread(){ @Override public void run() { 下載大數(shù)據(jù)集代碼 } }
最后測試了下50w這樣子的person數(shù)據(jù)的下載,大概耗時(shí)9秒,100w的person數(shù)據(jù),耗時(shí)19秒。這樣子的下載效率,應(yīng)該可以滿足大部分公司的報(bào)表導(dǎo)出需求吧。
“用java怎么快速從系統(tǒng)報(bào)表頁面導(dǎo)出20w條數(shù)據(jù)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。