2013-03-25 63 views
2

最近我浏览了微型ORM,我喜欢SQLite的Massive,因为它很简单。但我现在有一个问题。使用Massite和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; 
} 

如果情况是海量没有关闭连接,并根据this SO question SQLite是不擅长的并发连接,我应该关闭它,我怎么可以关闭它呢? - 连接不会暴露给我。

我想听听开发人员使用SQLite的Massive的最佳做法。

+0

SQLite的不应该抱着除非事务是打开的锁。是持有交易的东西吗?为什么? – 2013-03-26 13:12:49

+0

Massive中的select语句不使用事务,但它看起来像这样:“var firstCustomerName = customers.First()。FirstName;”锁定数据库,以便以下更新不起作用; var c = tbl.Update(new {FirstName =“Updated2”},4); – antew 2013-03-26 14:39:58

回答

3

SQlite喜欢有一个打开的连接。

海量正确管理连接但它留下ExecuteReader“开放”,其中可以cause troubles:

罗伯特·辛普森写了Query method

离开读者开放可能导致的问题。这些不会被清理干净 ,直到懒惰垃圾收集器解决它。在任何情况下,最好在 附近使用()语句的时候肯定是 。以下对象使用 垃圾回收器会偷懒一下清理非托管资源:

SQLiteCommand,SQLiteConnection,SQLiteDataReader,并可能 SQLiteTransaction如果我没有记错。

所以就把ExecuteReader()围绕usingQuery方法,它应该很好地工作:

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(); ; 
      } 
     } 
    } 
} 

的一些注意事项和其他解决方法,其不要求改变的大规模来源:

  • 你可以启用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; 
    
+0

非常感谢,实际上我发现有一些发现收益率回报是问题(将连接断开),但是您向我确认了这一点! – antew 2013-04-14 19:06:51