“数据库已锁定”;在SQLite中使用Massive时的异常

本文关键字:Massive 异常 SQLite 数据库 锁定 | 更新日期: 2023-09-27 18:05:34

最近我浏览了微orm,我喜欢SQLite的Massive,因为它很简单。但我现在有一个问题。

我只是运行一些选择语句之后的更新语句,但我得到一个异常。下面是我的代码:

 var tbl = new Cust();
            var customers = tbl.All(where: "CustomerID > @0", orderBy: "FirstName", columns: "CustomerID,FirstName", args: 4);
            var firstCustomerName= customers.First().FirstName;
            var c = tbl.Update(new { FirstName = "Updated2" }, 4); //Exception is here!
            //Same happens even when using another object
            //var tbl2 = new Cust();
            //tbl2.Update(new { FirstName = "UpdatedName" }, 4);//Exception is here!

异常消息是:"Database is locked",在Massive下面的方法中。SQLite源码

public virtual int Execute(IEnumerable<DbCommand> commands)
{
       var result = 0;
            using (var conn = OpenConnection())
            {
                using (var tx = conn.BeginTransaction())
                {
                    foreach (var cmd in commands)
                    {
                        cmd.Connection = conn;
                        cmd.Transaction = tx;
                        result += cmd.ExecuteNonQuery();
                    }
                    tx.Commit();//Here is the Exception!
                }
            }
            return result;     
}

当我看到Massive。在SQLite源代码中,我看到massive从来没有关闭连接,而是依赖于using语句来处理连接对象,正如你在上面的代码中看到的那样。

上面代码中的OpenConnection()是一个每次调用都会返回一个新连接的方法。

 public virtual DbConnection OpenConnection()
 {
            var result = _factory.CreateConnection();
            result.ConnectionString = ConnectionString;
            result.Open();
            return result;
 }

如果情况是Massive没有关闭连接,并且根据这个SO问题Sqlite不擅长并发连接,我应该关闭它,那么我该如何关闭它?-连接不暴露给我。

我想听听开发人员在SQLite中使用Massive的最佳实践。

“数据库已锁定”;在SQLite中使用Massive时的异常

SQlite喜欢只打开一个连接。

Massive正在正确地管理连接,但是它在Query方法中留下ExecuteReader"打开",这可能会导致麻烦:

Robert Simpson写道:

打开阅读器可能会导致问题。那些不会被清理的直到懒惰的垃圾回收器找到它。当然是在任何情况下,在reader周围使用using()语句都是更好的至少是这样。以下对象使用非托管资源垃圾收集器将懒得清理:

SQLiteCommand, SQLiteConnection, SQLiteDataReader等如果我没记错的话。

因此,在Query方法中,将using放在ExecuteReader()周围,它应该可以正常工作:

public virtual IEnumerable<dynamic> Query(string sql, params object[] args)
{
    using (var conn = OpenConnection())
    {
        using (var rdr = CreateCommand(sql, conn, args).ExecuteReader())
        {
            while (rdr.Read())
            {
                yield return rdr.RecordToExpando(); ;
            }
        }
    }
}

一些不需要更改Massive源代码的注意事项和其他解决方法:

  • 您可以在SQLite中使用Pooling设置启用连接池:

    connectionString="Data Source=test.db;Version=3;Pooling=True;Max Pool Size=100;"
    
  • Query通常工作正确,如果它从读取器读取所有数据。但是您使用了First(),它与yield return结合使用,使阅读器打开。因此,如果您使用ToArray()评估查询,它也将工作:

    var firstCustomerName= customers.ToArray().First().FirstName;