2017-02-24 44 views
0

我想這樣做:的SQLite一直這樣做SELECT + UPDATE時鎖定我的數據庫(C#)

  1. 閱讀從一個SQLite數據庫行(在GetRuleByID()方法)
  2. 更新同一行我在剛纔讀(1)(見UpdateStatusForRuleID()方法)

但我的問題是,SQLite的在SELECT中GetRuleByID(後鎖定數據庫中),所以當所謂的在UpdateStatusForRuleID()的更新是唯一成功第一次。

我已經嘗試啓用SQLite以及PRAGMA read_uncommitted = 1日誌記錄以避免SQLite鎖定數據庫的SELECT,但這似乎不工作。

這應該很簡單,但我到目前爲止花了整整一個晚上試圖解決這個問題...請幫助!

private static MicroRuleEngine.Rule GetRuleByID(int ruleID, SQLiteConnection connection, out Dictionary<string, string> dict) 
{ 
    dict = new Dictionary<string, string>(); 

    string sql = String.Format("select * from rules WHERE ID = {0} ", ruleID.ToString()); 
    SQLiteCommand command = new SQLiteCommand(sql, connection); 
    SQLiteDataReader reader = command.ExecuteReader(); 

    if (reader.HasRows) 
    { 
     reader.Read(); 

     // Convert row into a dictionary 
     for (int lp = 0; lp < reader.FieldCount; lp++) 
     { 
      dict.Add(reader.GetName(lp), reader.GetValue(lp) as string); 
     } 

     string json = dict["fulljson"]; 
     MicroRuleEngine.Rule r = Newtonsoft.Json.JsonConvert.DeserializeObject<MicroRuleEngine.Rule>(json); 

     //command.Dispose();    

     return r; 
    } 

}

internal static void UpdateStatusForRuleID(SQLConnectionManager DBMANAGER, int ruleID, bool status) 
{ 
    Dictionary<string, string> dict = null; 

    string dbVal = (status) ? "1" : "0"; 
    MicroRuleEngine.Rule r = null; 
    string newJSON = null; 

    using (SQLiteConnection connection = DBMANAGER.CreateConnection()) 
    { 
     r = GetRuleByID(ruleID, connection, out dict); 
     r.Active = (status); 
     newJSON = Newtonsoft.Json.JsonConvert.SerializeObject(r); 

     Thread.Sleep(1000); 

     string sql = "UPDATE rules SET active = @a, [email protected] WHERE ID = @i"; 

     using (var command = new SQLiteCommand(sql, connection)) 
     { 
      command.Parameters.Add(new SQLiteParameter("@a", dbVal)); 
      command.Parameters.Add(new SQLiteParameter("@i", ruleID)); 
      command.Parameters.Add(new SQLiteParameter("@j", newJSON)); 

      command.ExecuteNonQuery(); // Database is locked here ??? 
     } 

     connection.Close(); 
    } 

}

+1

1.從上面的代碼我沒有看到兩種方法之間的關係2.你是什麼意思的'鎖',以及如何確定是否鎖定? –

+0

第一部分爲命令對象創建一個using塊。在第二部分中,connection.Close();可以留下,因爲你實現了use-block和.Close();內部只需調用.Dispose();這是由你的使用塊完成的。進一步說,你有什麼理由使用Thread.Sleep(1000); ??? – Sebi

+0

那麼調用代碼調用UpdateStatusForRuleID(),然後在執行實際的UPDATE命令之前調用GetRuleByID()。 –

回答

0

「數據庫被鎖定」 指的是一些其它連接(在相同的或其他一些方法)仍然具有活性的事務。

你不需要多個連接(除非你使用多個線程)。只需使用單個連接對象進行所有數據庫訪問。

確保所有命令,讀卡器和交易對象(連接,如果你決定使用暫時的)被正確地清理,通過使用using

using (var command = new SQLiteCommand(sql, connection)) 
using (var reader = command.ExecuteReader()) 
{ 
    if (reader.HasRows) 
    ... 
} 
0

顯然,下面的作品的代碼。我基本上刪除了GetRuleByID()方法(但後來我不得不重寫其他4種方法)

感謝所有提供了輸入的人。

 internal static void UpdateStatusForRuleID(SQLConnectionManager DBMANAGER, int ruleID, bool status) 
    { 
     string dbVal = (status) ? "1" : "0"; 
     MicroRuleEngine.Rule r = null; 
     string newJSON = null; 

     using (SQLiteConnection conn = DBMANAGER.CreateConnection()) 
     { 
      string sql = String.Format("select * from rules WHERE ID = {0} ", ruleID.ToString()); 

      using (var command = new SQLiteCommand(sql, conn)) 
      using (var reader = command.ExecuteReader()) 
      { 
       if (reader.HasRows) 
       { 
        reader.Read(); 

        string json = reader["fulljson"].ToString(); 
        r = Newtonsoft.Json.JsonConvert.DeserializeObject<MicroRuleEngine.Rule>(json); 
        r.Active = (status); 
        newJSON = Newtonsoft.Json.JsonConvert.SerializeObject(r); 

        string sql2 = "UPDATE rules SET active = @a, [email protected] WHERE ID = @i"; 

        using (var command2 = new SQLiteCommand(sql2, conn)) 
        { 
         command2.Parameters.Add(new SQLiteParameter("@a", dbVal)); 
         command2.Parameters.Add(new SQLiteParameter("@i", ruleID)); 
         command2.Parameters.Add(new SQLiteParameter("@j", newJSON)); 

         command2.ExecuteNonQuery(); 
        } 
       } 
      } 
     } 
    }