2015-04-29 81 views
2

我想了解如何安全地增加計數器列,這可能會被許多用戶(它是一個移動應用程序的Web API)同時增加。使用簡單更新計數器列的原子增量

我讀過流行的問題在SO處理這一問題的策略,但我似乎無法弄清楚什麼是錯用一個簡單的:

UPDATE Table SET Counter = Counter + 1 

我已經建立了下面的代碼示例嘗試並獲得一致的價值觀和證明自己,只用這個簡單的更新語句是不是好的做法:

class Program 
{ 
    static void Main(string[] args) 
     { 
      List<Task> tasks = new List<Task>(); 

      for (int i = 0; i < 100; i++) 
      { 
       Task t = Task.Factory.StartNew(() => 
       { 
        WriteToCounter(); 
       }); 

       tasks.Add(t); 
      } 

      Task.WaitAll(tasks.ToArray()); 
     } 

    static void WriteToCounter() 
     { 
      string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; 

      using (SqlConnection connection = new SqlConnection(connString)) 
      { 
       connection.Open(); 
       Random rnd = new Random(); 
       for (int i = 1; i <= 100; i++) 
       { 
        int wait = rnd.Next(1, 3); 
        Thread.Sleep(wait); 

        string sql = "UPDATE Table SET Counter = Counter + 1"; 

        SqlCommand command = new SqlCommand(sql, connection); 
        command.ExecuteNonQuery(); 
       } 
      } 
     } 
} 

在樣品我試圖模擬許多用戶同時訪問API和更新計數器的場景。代碼運行時,計數器爲始終爲10000,這意味着它是一致的。

測試是否正確模擬我描述的場景?
如果是這樣,我怎麼能使用更新語句沒有任何特殊的鎖定/交易策略,仍然得到一致的結果?

+0

不知道爲什麼它被投下。 – gdoron

回答

2

如果你只使用過它這麼簡單,你沒事。

的問題開始的時候:

  • 你添加一個條件 - 在大多數情況都很好,但要避免濾波基於Counter,這是一個偉大的方式失去決定一個交易
  • 更新(注意這一點 - 在實際更新語句範圍之外的事務很容易,如果使用例如TransactionScope,則更容易)
  • 可以組合插入和更新(例如,通常的「如果不存在」插入模式) - 這個 如果你只有一個計數器,那麼這不是一個問題,但是對於多個計數器來說,很容易陷入這個陷阱;不是很難解決,除非你也有刪除,那麼它就成爲一個完全不同的聯盟:)
  • 也許如果你依賴Counter的值是一個唯一的自動遞增標識符。這很明顯,如果你分開selectupdate(不,update基於select沒有幫助不起作用 - 不像普通update,在select不與同一行更新序列化;這就是鎖定提示來),我不確定使用output是否安全。

當然,如果事務隔離級別發生變化,事情可能會非常不同。這實際上是導致錯誤的合法原因,因爲SQL連接池不會重置事務隔離級別,所以如果您更改它,您需要確保它不會影響您在SqlConnection上執行的任何其他SQL的游泳池。

1

爲什麼我可以在沒有任何特殊的鎖定/事務策略的情況下使用update語句,並且仍然可以獲得一致的結果?

因爲當您使用提供ACID保證的數據庫時,會自動獲得很多這些功能。

例如,每個DML query在一個事務中運行。在SQL Server中,默認情況下它將以autocommit模式運行。在這種模式下,如果您執行查詢並且沒有打開的事務,它將創建一個新的事務。如果查詢完成而沒有錯誤,它會自動提交事務。在另一個名爲implicit transactions的模式中,如果沒有打開的事務,它仍然會自動創建一個新的事務,但是它會讓用戶決定是否實際執行提交。

至於locks,這裏也有相當複雜的一點。有各種形式的鎖,試圖在允許併發性和避免不一致之間取得平衡。事實上,SQL Server具有專用類型的鎖,僅用於UPDATE,旨在確保兩次並行嘗試到相同的資源將被正確序列化(而不是允許嘗試重疊和潛在死鎖) 。

所以,很長的回答短,您在您的問題中顯示的UPDATE是完全有效的。