Mysql中select + update并發(fā)更新問題

一開始想的解決方案:

A、把select和update合并成一條sql

B、事務(wù),用同一個事務(wù)包裹select+update的操作。

分析:并不是包上事務(wù)就萬事大吉。因?yàn)槿绻瑫r有兩個事務(wù)都分別select到了相同的記錄,那么一樣會發(fā)生有一方的更新會失敗的問題。然后我再想到把事務(wù)的隔離級別設(shè)置為serializable,但是考慮到性能顯然不現(xiàn)實(shí)。

我們知道innodb是支持行鎖的,然后我就去查看看他的幾種鎖:讀共享鎖和寫?yīng)氄兼i。

? 讀共享鎖

是通過SQL的LOCK IN SHARE MODE,例:

Select * from parent where name =‘jones’LOCK IN SHARE MODE;

如果事務(wù)A先獲得了讀共享鎖,那么事務(wù)B仍然可以做讀操作。但是必須等事務(wù)A commit或者roll back之后才可以更新或者刪除加了讀共享鎖的行數(shù)據(jù)。-----但是這種鎖并解決不了我們的問題,因?yàn)槲覀儜?yīng)該要再查詢的時候就查到事務(wù)A commit或者roll back后的數(shù)據(jù)才是,才是數(shù)據(jù)別更新后的最新數(shù)據(jù)。

------如果想要解決上面的并發(fā)問題,采用讀共享鎖是不可以解決的

? 寫?yīng)氄兼i

通過SQL的select…for update獲得,例:

Select xxx from xxx for update;

Update xxx set xxx = #{xxx};

如果事務(wù)A先獲得了某行寫共享鎖,那么事務(wù)B就必須等待事務(wù)A commit或者roll back之后才可以訪問數(shù)據(jù)。

------如果想要解決上面的并發(fā)問題,采用寫?yīng)氄兼i是可以解決的

另外這里特別提醒下:UPDATE/DELETE SQL盡量帶上WHERE條件并在WHERE條件中設(shè)定索引過濾條件,否則會鎖表,性能可想而知有多差了。因?yàn)?/h4>

MySQL InnoDB默認(rèn)Row-Level Lock,所以只有「明確」地指定主鍵,MySQL 才會執(zhí)行Row lock (只鎖住被選取的數(shù)據(jù)) ,否則MySQL 將會執(zhí)行Table Lock (將整個數(shù)據(jù)表單給鎖住)。


但是寫?yīng)氄兼i是一種悲觀鎖機(jī)制,所以在大佬的指導(dǎo)下還有一種方式,可以避免悲觀鎖,就是樂觀鎖!

·樂觀鎖,類似CAS機(jī)制(應(yīng)該采取的方式)

其實(shí)也很簡單,首先在select的SQL不作任何修改,然后在update的SQL的where條件中加上select出來的。但是避免不了ABA問題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容