2014-10-26 83 views
1

我從一個寧靜的服務器上拖出大量的json。我使用谷歌的GSON庫來遍歷這個json,它效果很好。現在我想將所有json對象保存在我的sqlite數據庫中,但是我想使用事務來一次添加所有這些對象。如果你沒有在一個datastructe中準備好所有的對象,這很困難。由於我一次遍歷一個json對象,所以我想我必須將其存儲在數據結構中,例如arraylist或hashmap,然後使用數據庫事務來快速執行插入操作。然而......將大量數據(又稱爲20000個json對象)存儲到內存中的結構中可能佔用大量內存,並且可能會用完。將所有json對象放入我的sqlite數據庫中的最佳方式是什麼?同時,不要使用其他語言中的許多menory來存儲和插入,以便進行大量的回收。在android中存儲大量數據

回答

0

我知道這不是在Android中處理大型json輸入的最佳實現,但它確實很好。

所以我的解決方案很簡單:

在解析JSON代碼,利用預處理語句和數據庫事務執行插入。 因此,簡而言之,只要解析JSON對象,就可以使用準備好的語句和db事務將該信息插入到數據庫中,然後轉到下一個對象。

我剛剛從遠程服務器通過JSON和GSON抽取了210,000行,每個23個字段(即460萬個值),同時將所有這些值插入到設備上的SQLite3數據庫中,少於5個分鐘而不浪費任何內存。每次解析/插入迭代使用相同數量的內存,並在下一次迭代時進行清理。

所以是的,有解決方案。顯然,這不是商業應用程序或具有1000 000條記錄的表格的最佳解決方案,但對我的情況非常有用。

+0

如果它是最好的,你應該接受你自己的答案。這樣,未來的讀者將很容易找到解決方案。 – mithrop 2014-10-27 08:59:24

+0

我會在20小時內。 @mithrop – Janpan 2014-10-27 19:35:43

1

如果你想在一個獨特的時刻添加大量的數據:無論如何它會佔用大量的內存。 200 000個大的JSON對象需要一定的內存,並且您將而不是能夠更改它。

您可以保持這種行爲,但我認爲這不是一個很好的解決方案,因爲您在Android設備和服務器上都創建了巨大的內存消耗。如果您逐個接收數據並以這種方式添加數據會更好:但您需要控制服務器代碼。

如果你是絕對被迫保持這種行爲,也許你應該在同一時間接收所有的數據,解析它們在一個巨大的JSON對象,然後進行多個事務。檢查每個事務是否正確執行,如果沒有,則將數據庫恢復到良好狀態。這是一個非常糟糕的方式,恕我直言...但我不知道你所有的限制。

完成:避免一次只接收大量數據。多次請求獲取部分數據集會更好。它會使您的應用程序減少網絡依賴性:如果您將網絡斷開2秒,則可能只有一個請求會失敗。所以你將不得不重試只有一個請求,並再次收到一小部分數據。只有一個巨大的請求:如果你鬆動了網絡,你將不得不重試整個請求...

+0

Thx的意見。我同意這樣做並不理想,但我對項目的某些方面幾乎沒有控制權。將考慮多個數據塊而不是一個大的請求。然而,使用gson做它並不會創建任何大內存事務,因爲一次執行一個數據庫插入也沒有問題,因爲它可以回收內存,但需要很長時間。我想看看我是否可以在交易時保持數據庫的開放。 – Janpan 2014-10-26 17:19:39

0

你有沒有試過在Android內部數據庫(SQLite)中添加大量數據(我的意思是很多,在我的情況下是2600行數據)?

如果是這樣,你可以和我一樣走上同樣的道路。

我試過一個正常的InsertStatement,這是減慢速度的方法(在我的模擬器中10秒)。然後我嘗試了PreparedStatements。時間比較好,但仍然不能接受。 (6秒)。經過一段令人沮喪的編寫代碼的時間,然後扔掉它,我終於找到了一個很好的解決方案。

Android-OS提供InsertHelper作爲快速插入方式。

爲了讓你的性能的概述(用垃圾電腦模擬器上進行測量,試圖插入2600行數據):

Insert-Statement 
10 seconds 
Prepared-Statements 
6 seconds 
InsertHelper 
320 ms 

你甚至可以多用暫時禁用線程加快插入鎖。這將增加約30%的性能。然而,重要的是要確保每次只有一個線程正在使用數據庫,而不是因爲線程安全而插入數據。

public void fillDatabase(HashMap<String, int[]> localData){ 
     //The InsertHelper needs to have the db instance + the name of the table where you want to add the data 
     InsertHelper ih = new InsertHelper(this.db, TABLE_NAME); 
     Iterator<Entry<String, int[]>> it = localData.entrySet().iterator(); 
     final int firstExampleColumn = ih.getColumnIndex("firstExampleColumn"); 
     final int secondExampleColumn = ih.getColumnIndex("secondExampleColumn"); 
     final int thirdExampleColumn = ih.getColumnIndex("thirdExampleColumn"); 
     try{ 
     this.db.setLockingEnabled(false); 
       while(it.hasNext()){ 
         Entry<String, int[]> entry = it.next(); 
         int[] values = entry.getValue(); 
         ih.prepareForInsert(); 
         ih.bind(firstExampleColumn, entry.getKey()); 
         ih.bind(secondExampleColumn, values[0]); 
         ih.bind(thirdExampleColumn, values[1]); 
         ih.execute(); 
       } 
     }catch(Exception e){e.printStackTrace();} 
       finally{ 
         if(ih!=null) 
           ih.close(); 
         this.db.setLockingEnabled(true); 
       } 
     }