在高併發下,經常需要處理select之後,在業務層處理邏輯,再執行update的情況。
若兩個連線併發查詢同一條資料,然後在執行一些邏輯判斷或業務操作後,執行update,可能出現與預期不相符的結果。
在不使用悲觀鎖與複雜sql的前提下,可以使用樂觀鎖處理該問題,同時兼顧效能。
場景模擬:
假設一張表兩個字段,乙個id,乙個use_count。
表裡存了100個id,每個id對應自己的use_count。
當id每使用一次,use_count要加1。當use_count大於1000時,這個id就不能在被使用了(換句話說 無法從資料庫中查出)。
在高併發情況下,會遇到一種問題:假設資料表中有一條記錄為:id=123456, use_count=999
a與b兩個連線併發查詢這個id=123456,都執行下列sql:
select
*
from
table
where
id=123456
and
use_count < 1000;
a先執行,得到id=123456的use_count是999,之後在程式裡做了一些邏輯判斷或業務操作後執行sql:
update
table
set
use_count + 1
where
id=123456;
在a做判斷且沒有update之前,b也執行了查詢sql,發現use_count是999,之後它也會執行sql:
update
table
set
use_count + 1
where
id=123456;
但是,事實上b不應該取得這個id,因為a已經是第1000個使用者。
處理步驟如下:
1、新增第3個字段version,int型別,default值為0。version值每次update時作加1處理。
alter
table
table
add
column
version
int
default
'0'
not
null
after
use_count;
2、select時同時獲取version值(例如為3)。
select
use_count, version
from
table
where
id=123456
and
use_count < 1000;
3、update時檢查version值是否為第2步獲取到的值。
update
table
set
version=4, use_count=use_count+1
where
id=123456
and
version=3;
如果update的記錄數為1,則表示成功。
如果update的記錄數為0,則表示已經被其他連線update過了,需作異常處理。
總結,通過版本號可以解決重複操作,或者重複訊息如(kafka)的問題。
樂觀鎖 版本號解決鎖競爭問題
在高併發的場景下,經常會遇到這種情況 a請求過來,查詢出來一條資料,進行update操作,與此同時b請求也在這個時候過來,對這條資料進行查詢,並進行操作。此時就會出現b在a之後進行查詢操作,但是實際b的資料卻被a覆蓋。這種情況並不少見,有時候會為了避免這種情況,我們會引入鎖來解決這種問題,常見的比如...
併發控制中的樂觀鎖與悲觀鎖
在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。1 丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。2 髒讀 當乙個事務讀取其它完成一半事務的記錄...
併發問題中的悲觀鎖和樂觀鎖
1.悲觀鎖 很悲觀,每次去拿資料的時候都認為別人會修改,所以每次去拿資料都會 上鎖 操作完成後再 解鎖 在資料加鎖期間,其他人如果來拿資料就會等待,直到去掉鎖。好比搶廁所。資料庫中的悲觀鎖有 鎖表 鎖行 等。c 程式中有lock obj 2.樂觀鎖 很樂觀,認為一般情況不會被占用,自己先佔了在說,佔...