簡體   English   中英

SqliteException忙着iOS / Android Xamarin MVVMCross

[英]SqliteException busy iOS/Android Xamarin MVVMCross

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

鑒於下面的代碼,我們有幾個存儲庫,每個存儲庫構造一個下面的實例和一個與Sqlite數據庫的關聯連接。 想象一下,我們有一個Stocks Repository和一個Valuations Repository,將創建兩個SqliteDataService實例:SqliteDataService類型為Stocks,SqliteDataService類型為Valuations,每個都與Sqlite數據庫有連接。

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

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

我的問題是:

每個存儲庫創建連接是否有效,如果是,我們如何防范SqliteException:busy?

有更好的模式嗎? 即我們應該創建一個跨線程共享相同連接的非泛型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);
            }
        }

聽起來你有幾個選擇:

  1. 僅實例化一個SqliteDataService並將其引用傳遞給您的Stocks和Valuations對象,這似乎是最明智的,因為它們都在同一個DB上運行

  2. 實例化一個對象以用作服務外部的鎖,並將引用傳遞給SqliteDataService構造函數,以便鎖定由兩個服務共享。 我相信這會奏效,但我不是鎖定方面的專家。

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM