2014-11-04 50 views
1

我已經實施了SQliteOpenHelper與單例模式,並且它工作良好,直到現在。但考慮到以下順序:數據隔離與服務和Singleton SQliteOpenHelper

  • 片段開始交易,以更新記錄
  • 服務被觸發,讀取更新的數據由於某種原因
  • 交易失敗和被回滾

該服務將處理稍後回滾的未提交數據。所以看起來單身模式與服務耦合導致數據隔離問題。然而,我已經閱讀了很多推薦單身人士的帖子。在使用單例時如何處理這種情況?

public class MyApplication extends Application{ 
    private static MyApplication instance; 
    public MyApplication(){ 
     instance = this; 
    } 
    public static Context getContext(){ 
     return instance; 
    } 
} 

public class LocalDBHelper extends SQLiteOpenHelper{ 
    private static final int DATABASE_VERSION = 1; 
    private static final String DATABASE_NAME = "MyDB"; 
    private static final String LOG_TAG = "LocalDBHelper"; 

    private static LocalDBHelper instance = null; 
    /*private constructor to avoid direct instantiation by other classes*/ 
    private LocalDBHelper(){ 
     super(MyApplication.getContext(), DATABASE_NAME, null, DATABASE_VERSION); 
    } 
    /*synchronized method to ensure only 1 instance of LocalDBHelper exists*/ 
    public static synchronized LocalDBHelper getInstance(){ 
     if(instance == null){ 
      instance = new LocalDBHelper(); 
     } 
     return instance; 
    } 
    ... 
    ... 
} 

使用與交易:

SQLiteDatabase db = LocalDBHelper.getInstance().getWritableDatabase(); 
db.beginTransaction(); 
try{ 
.... 
... 
db.setTransactionSuccessful(); 
}catch(Exception e){ 
    e.printStackTrace(); 
} 
finally{ 
    db.endTransaction(); 
} 
+0

你應該檢查了這一點:http://blog.lemberg.co.uk/concurrent-database-access – 2014-11-04 09:28:59

+0

@ user2247689謝謝我已閱讀同一文章在3個不同的網站:)但它不處理交易或隔離,所以與問題無關。 – faizal 2014-11-04 09:31:28

+0

對不起,我沒有正確地閱讀這個問題。處理服務有點棘手,特別是當它們必須併發時。基本上我猜你會不得不使用'消息'?請參閱http://developer.android.com/guide/components/bound-services.html#Messenger – 2014-11-04 09:39:51

回答

2
  1. 服務的主線程上運行。它沒有它自己的線程。它只有在主線程完成工作後纔會執行。因此,在事務在活動/片段中運行時不會有服務啓動的風險。

  2. 兩個線程不能訪問相同的SQliteDatabase連接。該系統旨在允許每個線程從池中訪問唯一的連接。如果沒有可用的連接,其他線程將等待一個。如果需要等待足夠長的時間,您會看到類似於我在下面的手機中看到的logcat警告。所以單例模式補充了SQLite的線程安全性。

    W/SQLiteConnectionPool(12695): The connection pool for database 'xyz' has been unable to grant a connection to thread 6386 (AsyncTask #2) with flags 0x1 for 4.0 seconds. W/SQLiteConnectionPool(12695): Connections: 0 active, 1 idle, 0 available.

  3. 由於#2的結果,還有另一個線程,如果你使用一個單獨讀取未提交的數據沒有可能的方式。即使你不使用單例,SQLite默認提供了連接之間的數據隔離。見https://www.sqlite.org/isolation.html

結論:與一個單身讀取未提交的數據的唯一方法是,如果你是在同一個線程,並在交易結束之前。

+1

請注意,雖然如果未預先寫入日誌記錄未啓用,則連接池當前設置爲最大值1,但實際上這不是必需的,將來可能會更改。但是,每個線程將使用不同的會話並從池中獲取唯一的連接。 SQLite當然仍然會實現它自己的鎖定和併發模型。 – corsair992 2014-11-04 14:41:57

+0

謝謝@ corsair992。我將SQLiteDatabase實例與連接實例混淆了。我編輯了#2以反映您的評論。 – faizal 2014-11-04 14:56:06