最近我浏览了微型ORM,我喜欢SQLite Massive,因为它很简单。但我现在有一个问题。
我只是运行一些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没有关闭连接,并且根据this SO question Sqlite并不擅长并发连接而且我应该关闭它,那我怎么能关闭呢? - 连接不会暴露给我。
我想听听使用Massive和SQLite的开发人员的最佳实践。
答案 0 :(得分:4)
SQlite喜欢打开一个连接。
Massive正在正确管理连接,但它会Query method中的ExecuteReader
“打开”cause troubles:
让读者保持开放可能会导致问题。那些不会被清理干净 直到懒惰的垃圾收集器绕过它。它肯定是 无论如何,最好在读者周围使用using()语句 至少。以下对象使用非托管资源 垃圾收集者会对清理很懒惰:
SQLiteCommand,SQLiteConnection,SQLiteDataReader,以及可能 如果我没记错的话,SQLiteTransaction。
所以在using
方法的ExecuteReader()
周围添加一个Query
,它应该可以正常工作:
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;