通過樂觀鎖(版本號)降低併發時的鎖競爭問題

2021-09-29 20:25:02 字數 1896 閱讀 6567

在高併發下,經常需要處理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*fromtablewhereid=123456anduse_count < 1000;

a先執行,得到id=123456的use_count是999,之後在程式裡做了一些邏輯判斷或業務操作後執行sql:

updatetablesetuse_count + 1whereid=123456;

在a做判斷且沒有update之前,b也執行了查詢sql,發現use_count是999,之後它也會執行sql:

updatetablesetuse_count + 1whereid=123456;

但是,事實上b不應該取得這個id,因為a已經是第1000個使用者。

處理步驟如下:

1、新增第3個字段version,int型別,default值為0。version值每次update時作加1處理。

altertabletableaddcolumnversionintdefault'0'notnullafteruse_count;

2、select時同時獲取version值(例如為3)。

selectuse_count, versionfromtablewhereid=123456anduse_count < 1000;

3、update時檢查version值是否為第2步獲取到的值。

updatetablesetversion=4, use_count=use_count+1whereid=123456andversion=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.樂觀鎖 很樂觀,認為一般情況不會被占用,自己先佔了在說,佔...