“数据库已锁定”;在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正在正确地管理连接,但是它在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;