簡體   English   中英

將Massive與SQLite一起使用時,“數據庫被鎖定”異常

[英]“Database is locked” exception when using Massive with SQLite

最近我瀏覽了微型ORM,我喜歡Massive for 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;
 }

如果案例是Massive沒有關閉連接,並根據這個SO問題 Sqlite不擅長並發連接,我應該關閉它,我怎么能關閉它呢? - 連接不會暴露給我。

我想聽聽開發人員使用Massive和SQLite的最佳實踐。

SQlite喜歡打開一個連接。

Massive正確管理連接,但它在Query方法中將ExecuteReader “open”,這可能會導致麻煩:

羅伯特辛普森寫道:

讓讀者保持開放可能會導致問題。 在懶惰的垃圾收集器到達它之前,這些將不會被清理干凈。 在任何情況下,至少在讀者周圍使用using()語句肯定會更好。 以下對象使用垃圾收集器將在清理時懶惰的非托管資源:

如果我沒記錯的話,SQLiteCommand,SQLiteConnection,SQLiteDataReader以及可能的SQLiteTransaction。

因此,在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; 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM