2013-03-25 107 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