在高併發的場景下,經常會遇到這種情況:
a請求過來,查詢出來一條資料,進行update操作,與此同時b請求也在這個時候過來,對這條資料進行查詢,並進行操作。此時就會出現b在a之後進行查詢操作,但是實際b的資料卻被a覆蓋。
這種情況並不少見,有時候會為了避免這種情況,我們會引入鎖來解決這種問題,常見的比如使用reetrantlock或者synchronized同步塊等悲觀鎖的方式來實現,其實在這裡,我們也可以嘗試使用樂觀鎖+版本號的方式來進行處理。
可以舉個更具體的案例來說明一下。
a請求
select num from store where id='1';
此時獲取到num=99
這時候b請求進來後,也發起查詢
select num from store where id='1';
此時由於a請求尚未進行update,b請求獲取到的num也等於99。
這時候a進行update操作
update store set num =$ +1 where id='1';
這時候寫入資料庫的num即為100
此時b請求也發起了更新操作:
update store set num =$ +1 where id='1';
這時候我們的預期本應該是101的,但是實際上b又在資料庫寫入了100.
解決方案:
這時候我們可以引入乙個版本號的概念,來巧妙的解決這個問題。
a請求
select num,version from store where id='1';
此時假設num=99,version=1,這時候b依然發起select請求:
select num,version from store where id='1';
沒有意外,b取到的version也是1,這時候a進行update寫入,此時:
update store set num =$ +1,version=$+1 where id='1' and version='1'
由於a進行行級鎖,此時version也變成了2。
b這時候發起操作,由於select的時候,版本號依然為1,此時實際b無法進行update的
update store set num =$ +1,version=$+1 where id='1' and version='1'
我們可以看到由於在資料庫的版本號已經變成2,了,實際version=1會讓b請求的更新資料不能成功。 通過樂觀鎖(版本號)降低併發時的鎖競爭問題
在高併發下,經常需要處理select之後,在業務層處理邏輯,再執行update的情況。若兩個連線併發查詢同一條資料,然後在執行一些邏輯判斷或業務操作後,執行update,可能出現與預期不相符的結果。在不使用悲觀鎖與複雜sql的前提下,可以使用樂觀鎖處理該問題,同時兼顧效能。場景模擬 假設一張表兩個字...
樂觀鎖解決併發問題
為什麼需要鎖 在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。髒讀 當乙個事務讀取其...
樂觀鎖與悲觀鎖 解決併發問題
引言 為什麼需要鎖 併發控制 在多使用者環境 中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 為了解決這些併發帶來的問題。我們需要引入併發控制機制。悲觀鎖 假定會發生併發衝突,遮蔽一切可能違反資料完整性的操作。1 樂觀鎖 假設不會發生併發衝突,只在...