繁体   English   中英

将Massive与SQLite一起使用时,“数据库被锁定”异常

[英]“Database is locked” exception when using Massive with SQLite

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

我只是运行一些select语句后跟一个更新语句,但我得到一个例外。 以下是我的代码:

 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!

异常消息是:“数据库被锁定”,在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源代码时,我看到大量从不关闭连接,而是继续使用using语句来处理连接对象,如上面的代码所示。

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

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

如果案例是Massive没有关闭连接,并根据这个SO问题 Sqlite不擅长并发连接,我应该关闭它,我怎么能关闭它呢? - 连接不会暴露给我。

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

SQlite喜欢打开一个连接。

Massive正确管理连接,但它在Query方法中将ExecuteReader “open”,这可能会导致麻烦:

罗伯特辛普森写道:

让读者保持开放可能会导致问题。 在懒惰的垃圾收集器到达它之前,这些将不会被清理干净。 在任何情况下,至少在读者周围使用using()语句肯定会更好。 以下对象使用垃圾收集器将在清理时懒惰的非托管资源:

如果我没记错的话,SQLiteCommand,SQLiteConnection,SQLiteDataReader以及可能的SQLiteTransaction。

因此,在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; 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM