大文本數(shù)據(jù)的數(shù)據(jù)庫存儲

要點####

  • 文件數(shù)據(jù)的讀取相較數(shù)據(jù)庫的存儲較快
  • Android系統(tǒng)對單個應(yīng)用的內(nèi)存有限制
  • 數(shù)據(jù)庫操作中對數(shù)據(jù)的批插入比單個插入效率更高
  • 合理利用多線程能夠大大提高工作效率

背景####

項目有一個需求就是將文本文件解析歹垫,然后保存到數(shù)據(jù)庫中镀迂。最初的思考方式是采用讀取文件一行數(shù)據(jù)(按行存儲一個實體變量數(shù)據(jù))同窘,解析數(shù)據(jù)為實體類辉阶,然后將該實體類存儲至數(shù)據(jù)庫中沃但;該方法在測試過程中有一個致命缺點:處理時間長可款。

分析####

將上述流程轉(zhuǎn)化為比較容易理解的抽象圖,如下:

文件數(shù)據(jù)保存至數(shù)據(jù)庫(未優(yōu)化).png

將子公司貨物(單行數(shù)據(jù))快速打包成貨物(解析)并運送至交接位置處(內(nèi)存)逼庞,然后交由速度較慢的運送方式將貨物運送至總部(數(shù)據(jù)庫)蛇更。該方式為順序流程,當貨物運送至總部后才會再次從子公司重新開始運送貨物赛糟。該方式有幾個缺點:

  • 順序流程增加了總時間:數(shù)據(jù)插入時間+數(shù)據(jù)的處理時間派任,如果采用多線程將會大幅度減少總時間
  • 數(shù)據(jù)的單個插入增加了數(shù)據(jù)插入時間

優(yōu)化####

通過分析將流程優(yōu)化,優(yōu)化后的抽象圖如下:


文件數(shù)據(jù)保存至數(shù)據(jù)庫(已優(yōu)化).png

該流程分為兩部分:

  • 將子公司貨物(單行數(shù)據(jù))快速打包成貨物(解析)并運送至倉庫(內(nèi)存隊列)璧南;
  • 從倉庫中取出合適數(shù)量的貨物(批量數(shù)據(jù))運送至總部(數(shù)據(jù)庫)

??該流程利用了多線程將流程分為兩部分——數(shù)據(jù)存儲數(shù)據(jù)解析掌逛,數(shù)據(jù)存儲的速度較慢,因此最后總時間的計算是以數(shù)據(jù)存儲為依據(jù)司倚,也就是數(shù)據(jù)插入時間豆混。
??另一方面,程序使用了倉庫动知,也就是隊列的方式優(yōu)化了數(shù)據(jù)的交接方式皿伺,將數(shù)據(jù)存儲與數(shù)據(jù)解析分離,他們只通過隊列才產(chǎn)生耦合盒粮。但是因為Android對內(nèi)存的限制鸵鸥,所以需要合理設(shè)計倉庫的大小,以防出現(xiàn)內(nèi)存溢出丹皱。

注意:合理的設(shè)計數(shù)據(jù)解析與數(shù)據(jù)存儲流程對隊列的數(shù)據(jù)讀寫速度妒穴。

Code####

??通過上述的代碼分析,應(yīng)該對整體的流程有一個大概的思路摊崭,現(xiàn)在我們來看一下代碼:

  • 隊列的定義與初始化:
LinkedBlockingQueue queue = new LinkedBlockingQueue();
  • 主要流程代碼:
try {
    BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(path))));
    String line = null;
    //初始化數(shù)據(jù)存儲線程
    WriteDB writeDB = new WriteDB();
    new Thread(writeDB).start();
    //讀取文本文件讼油,并解析
    while ((line = reader.readLine())!=null){
        //通過該函數(shù)解析數(shù)據(jù)
        parase(line);
        //查詢隊列中的數(shù)據(jù)量,當數(shù)據(jù)為8000條時暫停數(shù)據(jù)解析線程
        if(queue.size() == 8000){
            Thread.currentThread().sleep(2*1000);
        }
    }
    reader.close();
    //告知數(shù)據(jù)存儲線程讀取線程結(jié)束
    writeDB.stop();

} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
}
  • 數(shù)據(jù)解析流程:
private void parase(String s) throws Exception{
     //根據(jù)規(guī)則解析單行數(shù)據(jù)爽室,并轉(zhuǎn)化為實體
     String[] list = s.split("\\|");
     BagInfo bag = new BagInfo();
     bag.setBagID(list[0]);
     bag.setPileID(list[1]);
     bag.setTrayID(list[2]);
     //存入隊列中
     queue.put(bag);
}
  • 數(shù)據(jù)存儲流程:
class WriteDB implements Runnable {
    private boolean isRun = true;
    @Override
    public void run() {
        //為了批量存儲設(shè)置的列表汁讼,保存從隊列中讀取的數(shù)據(jù)
        List<BagInfo> bagInfos = new ArrayList<>();
        while (isRun || !queue.isEmpty()){
            Object obj = null;
            try {
                obj = queue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            bagInfos.add((BagInfo) obj);
            //當列表中的數(shù)據(jù)量達到2000時將數(shù)據(jù)批量存儲至數(shù)據(jù)庫中
            if(bagInfos.size() == 2000){
                DBService.getService().getBagInfoDao().insertInTx(bagInfos);
                bagInfos.clear();
            }
        }
        //處理當總數(shù)據(jù)量不是2000的整數(shù)倍時所剩余的數(shù)據(jù)
        if(!bagInfos.isEmpty()){
            DBService.getService().getBagInfoDao().insertInTx(bagInfos);
            bagInfos.clear();
        }
        queue = null;
    }

    public void stop(){
        isRun =false;
    }
}

后臺監(jiān)測####

??運行程序并監(jiān)測后臺,發(fā)現(xiàn)內(nèi)存基本穩(wěn)定在6M左右阔墩;測試5W多條的數(shù)據(jù)量總花費的時間為68s左右嘿架。監(jiān)測圖如下:

后臺監(jiān)測圖.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市啸箫,隨后出現(xiàn)的幾起案子耸彪,更是在濱河造成了極大的恐慌,老刑警劉巖忘苛,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝉娜,死亡現(xiàn)場離奇詭異唱较,居然都是意外死亡,警方通過查閱死者的電腦和手機召川,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門南缓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人荧呐,你說我怎么就攤上這事汉形。” “怎么了倍阐?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵概疆,是天一觀的道長。 經(jīng)常有香客問我峰搪,道長岔冀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任概耻,我火速辦了婚禮使套,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鞠柄。我一直安慰自己童漩,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布春锋。 她就那樣靜靜地躺著,像睡著了一般差凹。 火紅的嫁衣襯著肌膚如雪期奔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天危尿,我揣著相機與錄音呐萌,去河邊找鬼。 笑死谊娇,一個胖子當著我的面吹牛肺孤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播济欢,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼赠堵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了法褥?” 一聲冷哼從身側(cè)響起茫叭,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎半等,沒想到半個月后揍愁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體呐萨,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年莽囤,在試婚紗的時候發(fā)現(xiàn)自己被綠了谬擦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡朽缎,死狀恐怖惨远,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饵沧,我是刑警寧澤锨络,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站狼牺,受9級特大地震影響羡儿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜是钥,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一掠归、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧悄泥,春花似錦虏冻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鸥鹉,卻和暖如春蛮穿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背毁渗。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工践磅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灸异。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓府适,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肺樟。 傳聞我的和親對象是個殘疾皇子檐春,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容