繁体   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