<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          求你了,別在高并發(fā)場(chǎng)景中使用悲觀鎖了!

          共 2299字,需瀏覽 5分鐘

           ·

          2022-06-20 22:17

          △Hollis, 一個(gè)對(duì)Coding有著獨(dú)特追求的人△
          這是Hollis的第 394 篇原創(chuàng)分享
          作者 l Hollis
          來源 l Hollis(ID:hollischuang)

          Hollis的新書限時(shí)折扣中,一本深入講解Java基礎(chǔ)的干貨筆記!

          我們知道,樂觀鎖和悲觀鎖是并發(fā)控制主要采用的技術(shù)手段,通常用在數(shù)據(jù)庫管理中。

          但是,樂觀鎖、悲觀鎖并不像行級(jí)鎖、共享鎖等概念一樣是真實(shí)存在的鎖。其實(shí)他們只是人們定義出來的概念,可以認(rèn)為是一種思想。 其實(shí)不僅僅是關(guān)系型數(shù)據(jù)庫系統(tǒng)中有樂觀鎖和悲觀鎖的概念,像memcache、hibernate、tair等都有類似的概念。

          針對(duì)于不同的業(yè)務(wù)場(chǎng)景,應(yīng)該選用不同的并發(fā)控制方式。所以,不要把樂觀并發(fā)控制和悲觀并發(fā)控制狹義的理解為DBMS中的概念,更不要把他們和數(shù)據(jù)中提供的鎖機(jī)制(行鎖、表鎖、排他鎖、共享鎖)混為一談。其實(shí),在DBMS中,悲觀鎖正是利用數(shù)據(jù)庫本身提供的鎖機(jī)制來實(shí)現(xiàn)的。

          網(wǎng)上有很多關(guān)于樂觀鎖和悲觀鎖的介紹,我之前也有文章(《深入理解樂觀鎖與悲觀鎖》)專門介紹過,這里為了方便大家理解,就簡(jiǎn)單做個(gè)總結(jié)。



          悲觀鎖和樂觀鎖

          悲觀鎖,正如其名,它指的是對(duì)數(shù)據(jù)被外界修改持悲觀態(tài)度,因此,在整個(gè)數(shù)據(jù)處理過程中,需要先將數(shù)據(jù)進(jìn)行鎖定,獲得鎖之后再進(jìn)行操作。

          在MySQL中,可以使用排他鎖來實(shí)現(xiàn)悲觀鎖,主要就是用到select ... for update語法。

          要使用悲觀鎖,需要關(guān)閉mysql數(shù)據(jù)庫的自動(dòng)提交屬性:set autocommit=0;

          然后在事務(wù)中,通過如下語句對(duì)數(shù)據(jù)進(jìn)行加鎖:

          select status from t_goods where id=1 for update

          以上,在對(duì)id = 1的記錄修改前,先通過for update的方式進(jìn)行加鎖,然后再進(jìn)行修改。這就是比較典型的悲觀鎖策略。

          如果以上修改庫存的代碼發(fā)生并發(fā),同一時(shí)間只有一個(gè)線程可以開啟事務(wù)并獲得id=1的鎖,其它的事務(wù)必須等本次事務(wù)提交之后才能執(zhí)行。這樣我們可以保證當(dāng)前的數(shù)據(jù)不會(huì)被其它事務(wù)修改。

          相對(duì)悲觀鎖而言,樂觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會(huì)造成沖突,所以在數(shù)據(jù)進(jìn)行提交更新的時(shí)候,才會(huì)正式對(duì)數(shù)據(jù)的沖突與否進(jìn)行檢測(cè),如果發(fā)現(xiàn)沖突了,則讓返回用戶錯(cuò)誤的信息,讓用戶決定如何去做。

          樂觀鎖的實(shí)現(xiàn)并不會(huì)使用數(shù)據(jù)庫提供的鎖機(jī)制。一般的實(shí)現(xiàn)樂觀鎖的方式就是記錄數(shù)據(jù)版本,如以下SQL:

           update t_goods     
           set status=2,version=version+1    
           where id=#{id} and version=#{version}

          二者區(qū)別

          以上,我們了解了樂觀鎖和悲觀鎖的思想以及實(shí)現(xiàn)了之后,討論一下他們的區(qū)別。

          首先,在加鎖時(shí)間上有所不同,悲觀鎖是在事務(wù)剛開始的時(shí)候就加鎖,在拿到鎖之后再去進(jìn)行業(yè)務(wù)操作。而樂觀鎖是在更新的那一刻才會(huì)進(jìn)行并發(fā)控制,所以是先進(jìn)行的業(yè)務(wù)操作。

          其次,悲觀鎖主要是借助數(shù)據(jù)庫的排他鎖實(shí)現(xiàn)的,而排他鎖本質(zhì)上是一種阻塞鎖。 如果并發(fā)量比較大并且沖突比較多的時(shí)候,會(huì)導(dǎo)致很多線程被鎖阻塞,導(dǎo)致請(qǐng)求的RT被拉長(zhǎng),并且會(huì)占用大量的數(shù)據(jù)庫鏈接。

          相比之下,樂觀鎖不會(huì)造成阻塞,但是他帶來的問題就是如果并發(fā)的沖突比較高的話,那么就會(huì)有很多失敗的情況,需要業(yè)務(wù)代碼做好這種失敗的特殊處理。

          第三點(diǎn),那就是樂觀鎖雖然叫鎖,但是他并沒有額外加鎖,它是通過CAS來實(shí)現(xiàn)的,所以他的效率比較高,而悲觀鎖需要利用數(shù)據(jù)庫的鎖機(jī)制進(jìn)行加鎖,這會(huì)帶來一定的額外消耗。

          還有最后一點(diǎn),也是比較重要的一點(diǎn),那就是悲觀鎖因?yàn)樽隽思渔i的動(dòng)作,所以是會(huì)導(dǎo)致死鎖的。


          高并發(fā)不要使用悲觀鎖

          我強(qiáng)烈建議大家,優(yōu)先使用樂觀鎖,尤其是并發(fā)比較高,并且沖突也比較多的場(chǎng)景。

          因?yàn)槲覀兦懊嫣岬竭^,悲觀鎖會(huì)有額外的消耗、并且可能會(huì)帶來死鎖。但是這些都不是最重要的。

          最重要的是,悲觀鎖本質(zhì)上是一種阻塞鎖,在并發(fā)比較高的情況下,會(huì)有很多個(gè)線程都被阻塞,而這些阻塞的線程是會(huì)占用數(shù)據(jù)庫鏈接的。所以這時(shí)候就會(huì)導(dǎo)致你的系統(tǒng)的并發(fā)度很低,還有就是這些阻塞的線程的響應(yīng)時(shí)長(zhǎng)也會(huì)被拉的很長(zhǎng),極度影響用戶體驗(yàn),也會(huì)多出來很多慢SQL。

          額外提一句,在MySQL 8.0中,已經(jīng)支持了select ... for update nowait,可以把阻塞鎖變成非阻塞的??梢栽谀撤N程度上解決悲觀鎖的阻塞帶來的一些問題,但是加鎖的額外開銷和死鎖的問題也還是有的。

          所以,高并發(fā)場(chǎng)景中,建議大家使用樂觀鎖,尤其是MySQL 5.x 的版本中,因?yàn)椴恢С?strong>nowait,一旦使用悲觀鎖,會(huì)大大降低你的系統(tǒng)的并發(fā)度。


           


          我的新書《深入理解Java核心技術(shù)》已經(jīng)上市了,上市后一直蟬聯(lián)京東暢銷榜中,目前正在6折優(yōu)惠中,想要入手的朋友千萬不要錯(cuò)過哦~長(zhǎng)按二維碼即可購買~


          長(zhǎng)按掃碼享受6折優(yōu)惠




          往期推薦

          知乎熱議:月薪 2~3W 的碼農(nóng),怎樣度過一天?


          還在用 SimpleDateFormat 做時(shí)間格式化?小心項(xiàng)目崩掉!


          入職一家新公司,如何快速熟悉代碼?



          如果你喜歡本文,
          請(qǐng)長(zhǎng)按二維碼,關(guān)注 Hollis.
          轉(zhuǎn)發(fā)至朋友圈,是對(duì)我最大的支持。

          點(diǎn)個(gè) 在看 
          喜歡是一種感覺
          在看是一種支持
          ↘↘↘
          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲午夜精品久久久 | 伊人操逼视频网 | 亚洲精选青青草日韩 | 天天碰人人操人人 | 欧美在线导航 |