[英]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);
}
}
聽起來你有幾個選擇:
僅實例化一個SqliteDataService並將其引用傳遞給您的Stocks和Valuations對象,這似乎是最明智的,因為它們都在同一個DB上運行
實例化一個對象以用作服務外部的鎖,並將引用傳遞給SqliteDataService構造函數,以便鎖定由兩個服務共享。 我相信這會奏效,但我不是鎖定方面的專家。
您可以在try catch塊中處理Busy異常,並迭代計數器以使用每次短暫的等待對數據庫進行最大次數嘗試,以便您有很好的連接機會。 如果數據庫仍然忙,你仍然會得到異常,這個解決方案非常混亂。
重構數據庫,使兩個區域分開,這可能是不可能的,但值得一想。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.