2015-04-22 67 views
6

在我們的Android和iOS MVVMCross應用程序中,偶爾會遇到SQLiteException:繁忙異常。SqliteException繁忙的iOS/Android Xamarin MVVMCross

鑑於下面的代碼,我們有幾個存儲庫,每個存儲庫構建下面的一個實例和一個到Sqlite數據庫的關聯連接。想象一下,我們有一個股票庫和一個估值庫,將創建SqliteDataService的兩個實例:SqliteDataService類型爲Stocks,SqliteDataService類型爲Valuations,每個類型都有一個到Sqlite數據庫的連接。

存儲庫上的操作可能在後臺線程上操作,這意味着我們可能會嘗試將庫存與Valuations同時插入數據庫。

現在給每個存儲庫創建自己的SqliteDataService,connectionObject鎖只會保護相同的存儲庫類型不能同時訪問數據庫,而不能保護Stocks和Valuations不能同時訪問數據庫。

我的問題是:

有效期是創建每個存儲庫連接,如果是的話,我們該如何防範SqliteException:忙什麼呢?

有更好的模式嗎?即我們是否應該創建一個非泛型的SqliteDataService類,該類在多個線程之間共享相同的連接?我們嘗試了這一點,但在Android上我們遇到了致命的例外情況。

有沒有人對Xamarin MVVMCross有一個堅實的Sqlite DAL模式?

public class SqliteDataService<T> : IDataService<T> where T : new() 
{ 
    private static object lockObject = new object(); 

    private static object connectionObject = new object(); 

    private static ISQLiteConnection _connection; 

    private static SqliteDataService<T> _instance; 

    public SqliteDataService(ISQLiteConnectionFactory connectionFactory, string dbPath) 
    { 
     if (_connection == null) 
     { 
      _connection = connectionFactory.Create (dbPath); 
      _connection.CreateTable<T>(); 
     } 
    } 

    public static SqliteDataService<T> GetInstance(ISQLiteConnectionFactory connectionFactory, string dbPath) 
    { 

     if (_instance == null) 
     { 
      lock (lockObject) 
      { 
       _instance = new SqliteDataService<T> (connectionFactory, dbPath); 
      } 
     } 

     return _instance; 
    } 

    public void CreateTable<T>() 
    { 

    } 

    public void Insert(T value) 
    { 
     lock (connectionObject) { 
      _connection.Insert (value, typeof(T)); 
     } 
    } 

    public void InsertAll(IEnumerable<T> values) 
    { 
     lock (connectionObject) { 
      _connection.Insert (values, typeof(T)); 
     } 
    } 

    public IEnumerable<T> Read(Expression<Func<T, bool>> predicate) 
    { 
     lock (connectionObject) { 
      return _connection.Table<T>().Where (predicate); 
     } 
    } 

    public T ReadFirst(Expression<Func<T, bool>> predicate) 
    { 
     lock (connectionObject) { 
      return Read (predicate).FirstOrDefault(); 
     } 
    } 

    public void Update(T value) 
    { 
     lock (connectionObject) { 
      _connection.Update (value, typeof(T)); 
     } 
    } 

    public void Delete(Expression<Func<T, bool>> predicate) 
    { 
     lock (connectionObject) { 
      var valuesToDelete = Read (predicate); 

      if (valuesToDelete == null) 
       return; 

      foreach (var value in valuesToDelete) { 
       _connection.Delete (value); 
      } 
     } 
+0

您是否解決了這個問題?如果它是固定的,請發表一個答案。 –

回答

0

這聽起來像你有幾個選擇:

  1. 僅實例化一個SqliteDataService並通過對它的引用您的股票和估值對象都,這似乎最明智的,因爲已在同一個數據庫上運行

  2. 實例化對象以用作服務外部的鎖,並將引用傳遞到SqliteDataService構造函數中,以便兩個服務共享該鎖。我相信這會起作用,但我並不擅長鎖定。

  3. 您可以在try catch塊中處理Busy異常,並每次迭代計數器以對數據庫執行最大嘗試次數,以便您有很好的連接機會。如果數據庫仍然很忙,你仍然會得到異常,這個解決方案相當混亂。

  4. 重構數據庫,使兩個區域分開,這可能是不可能的,但值得一想。