数据库
首页 > 数据库> > c#-将Massive与SQLite一起使用时,“数据库已锁定”异常

c#-将Massive与SQLite一起使用时,“数据库已锁定”异常

作者:互联网

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

我只是在运行一些select语句,然后执行update语句,但是却遇到异常.下面是我的代码:

 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源代码时,我看到Massive从未关闭连接,而是中继using语句来处理连接对象,如您在上面的代码中所看到的.

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

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

如果情况是Massive没有关闭连接,并且根据this SO question的说明,Sqlite在并发连接方面不擅长,并且我应该关闭它,那么我该如何关闭它呢? -连接没有暴露给我.

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

解决方法:

SQlite喜欢拥有一个打开的连接.

Massive正在正确管理连接,但是在Query method中它使ExecuteReader处于“打开”状态,它可以是cause troubles:

罗伯特·辛普森写道:

Leaving readers open could cause issues. Those won’t get cleaned up
until the lazy garbage collector gets around to it. It’d certainly be
better in any case to have using() statements around your readers at
the very least. The following objects use unmanaged resources that
the garbage collector will be lazy about cleaning up:

SQLiteCommand, SQLiteConnection, SQLiteDataReader, and possibly
SQLiteTransaction if I recall correctly.

因此,在Query方法中的ExecuteReader()周围放置一个use,它应该可以正常工作:

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中启用连接池:

connectionString="Data Source=test.db;Version=3;Pooling=True;Max Pool Size=100;"

>如果查询从读取器读取所有数据,则查询通常可以正常工作.但是您使用的是First(),它与收益率回报相结合,使阅读器保持打开状态.因此,如果您使用ToArray()评估查询,它也将起作用:

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

标签:massive,sqlite,c
来源: https://codeday.me/bug/20191031/1973084.html