2015年3月7日 星期六

[C#]Postgresql transaction

為什麼要用 Transaction(事務) 呢?

Transaction 中執行多條SQL,與我用分隔符號

sql1;sql2;sql3 這樣的差異在於Transaction 的寫入發生錯誤時,是可以將目前已寫的SQL 復原

(roll-Rollback)當作沒發生過,要嘛全寫要嘛全都不寫。而用分隔符號的,即使寫到一半發生

錯誤,前面的依然也寫進去了。尤其是當你把表頭和表身分開紀錄時,只有在commit之後,

才會一起看的到表頭和表身。

     /// <summary>  
     /// Postgresql Transaction  
     /// </summary>  
     /// <param name="list">sql</param>  
     /// <param name="connstr">ConnectionStr</param>  
     /// <returns></returns>  
     public bool TransactionDB(List<string> list, string connstr)  
     {  
       if (list.Count == 0)  
       {  
         return true;  
       }  
       NpgsqlTransaction tran = null; ;  
       NpgsqlCommand com = null;  
       NpgsqlConnection conn = null;  
       bool isCommit = true;        
       try  
       {  
         conn = new NpgsqlConnection(connstr);  
         //打開一個資料庫連接  
         conn.Open();  
         com = conn.CreateCommand();  
         //The IsolationLevel for this transaction. The default is ReadCommitted.  
         tran = conn.BeginTransaction(IsolationLevel.ReadCommitted);          
         for (int i = 0; i < list.Count; i++)  
         {  
           com.CommandText = list[i];  
           com.ExecuteNonQuery();            
         }  
         //Commit  
         tran.Commit();  
       }  
       catch (Exception eee)  
       {  
         isCommit = false;  
         try  
         {  
           if (conn.State == ConnectionState.Open)  
           {  
             //Rollback  
             tran.Rollback();  
           }  
         }  
         catch (Exception ex)  
         {  
           Console.WriteLine(ex.StackTrace);  
         }  
       }  
       finally  
       {  
         if (com != null)  
         {  
           com.Dispose();  
         }  
         if (conn.State == ConnectionState.Open)  
         {  
           conn.Close();  
         }  
       }  
       return isCommit;  
     }  


比較值得注意的是這一行,這代表交易的隔離層次,如果不設定,則預設隔格層次就是

Read Committed

 tran = conn.BeginTransaction(IsolationLevel.ReadCommitted); 

隔離層次主要是要處理當交易正在進行時,其他的查詢或交易動作是否可以讀寫資料,或取得的資料是不是已經完成交易或未完成交易的狀態


  • Read Uncommitted允許其他查詢在交易未完成時,就可以讀取交易範圍內的資源,這個層次會鎖定的範圍非常小 (幾乎不定),在多人環境下可以完成忽略交易可能造成的損耗,但卻會有很嚴重的 Dirty Read 問題。

  • Read Committed只允許其他查詢讀取已認可 (Committed) 的交易資料,這個層次會在交易認可前鎖定資源,認可後就釋放,它的優點是鎖定範圍小,對效能影響不大,而且可以保證資料的修改是已認可的,但它卻有可能會發生幽靈讀取 (Phantom Read) 的狀況,且它也會有不可重覆讀取 (Nonrepeatable read) 的問題
  • Repeatable Read:有時交易執行的範圍會很長,且可能在交易內重覆參考某些資源,這種時候如果外部交易修改了交易內的參考資源時,就會發生資料不一致的問題,而這個隔離層次就是在避免這個問題,它具有 Read Committed 的特性,但又不允許其他交易修改交易內參考到的資源,以保證資料是可重覆讀取 (Repeatable Read)          
  • Serializable 演算法是最穩固的一種隔離層次演算法,因為它強制所有的交易都必須              按照順序,而且外部的查詢在 Serialize 的交易結束前,都不能讀取在交易中被鎖定住    的資源 (資料列或資料表),這對資料正確性的保障是最完整的,但它因為鎖定了大範圍的資源,會對多人環境的資料庫效能造成影響,死結 (deadlock) 的機率也會提高。
           
           ※Dirty Read:意指在交易外的查詢讀到的資料會不一致,這是因為交易在認可前被讀
                       了一次 (s1),交易中修改了該值,而修改後認可前又被讀了一次 (s2),而這兩個值不一
                      致 (s1 != s2)

  • Phantom Read: 意指在查詢讀到的資料在資料表中不存在,這會發生在 INSERT DELETE 的狀況,例如交易進行時有新增資料或刪除資料,而外部查詢在交易完成前要查詢這筆新資料,或是在交易刪除資料後又可讀到被刪除的資料時,就是 Phantom Read 的錯誤狀態。 

沒有留言:

張貼留言