1. 程式人生 > >SQL處理併發之樂觀鎖

SQL處理併發之樂觀鎖

問題描述

在使用mysql資料庫儲存資料的前提下,有一個搶任務系統,一個任務只能分配給n個人,如果有高併發請求,如何保證資料完整性?

一般做法

在不考慮到資料是否完整的情況下,我們一般只會按照以下思維開發:

  1. 使用者請求搶任務介面
  2. 讀取資料庫剩餘數量
  3. 如果大於0,剩餘數量減1,更新資料庫剩餘數量(update task set count=count-1 where id=‘任務id’)
  4. 返回資料

出現的問題以及使用樂觀鎖概念解決

為什麼上面的做法不對呢?我們舉個例子,假設使用者1和使用者2同時呼叫請求搶任務介面,並且資料庫只剩下一個任務可搶,任務剩餘數量使用count欄位儲存;
使用者1和使用者2請求介面情況模擬,表格的每一行表示一個時間點

使用者1 使用者2
執行1 執行1
執行2 執行2
執行3(更新count為0)
執行3(更新count為-1)
執行4 執行4

通過以上的問題,我們不難知道,本來只有一個任務可搶的,現在被兩個使用者同時搶了,而且資料庫還出現了-1的情況,而這種情況再高併發的時候經常會遇到。

要解決高併發帶來的問題,就可以利用樂觀鎖的概念來解決。
將上面中的第3個步驟中是sql語句改為(update task set count=count-1 where id=1 and count=1)
當然,其中的count=1中的1是步驟2讀取出來的資料總數。
或者可以給表加一個版本號version欄位,預設為1,每次執行更新的時候自增1,並在where語句後帶上讀取到的版本號,以免再讀取和更新資料之間,有第三者更新了資料庫。

使用者1 使用者2
執行1 執行1
執行2 執行2
執行3(更新count,dao層返回1,表示更新成功)
執行3(更新count,dao層返回0,表示更新失敗)
執行4 執行4

最後結果

  1. 使用者請求搶任務介面
  2. 讀取資料庫剩餘數量
  3. 如果大於0,剩餘數量減1,更新資料庫剩餘數量(update task set count=count-1 where id=‘任務id’ and count=‘讀取到的剩餘數量’)
  4. 返回資料