溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何分析數(shù)據(jù)庫(kù)樂(lè)觀鎖、悲觀鎖

發(fā)布時(shí)間:2021-12-02 11:28:05 來(lái)源:億速云 閱讀:139 作者:柒染 欄目:大數(shù)據(jù)

今天就跟大家聊聊有關(guān)如何分析數(shù)據(jù)庫(kù)樂(lè)觀鎖、悲觀鎖,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

并發(fā)問(wèn)題

當(dāng)程序中出現(xiàn)并發(fā)的問(wèn)題時(shí),我們就要有相應(yīng)的手段保證數(shù)據(jù)的正確性,防止多個(gè)用戶(hù)在操作數(shù)據(jù)的時(shí)候,出現(xiàn)和預(yù)期數(shù)據(jù)不一樣的現(xiàn)象,產(chǎn)生臟數(shù)據(jù),在數(shù)據(jù)庫(kù)的層面如果沒(méi)有做好并發(fā)控制,就可能導(dǎo)致臟讀、幻讀和不可重復(fù)讀等問(wèn)題,所以對(duì)于并發(fā)場(chǎng)景鎖機(jī)制的應(yīng)用是非常有效的,保證了數(shù)據(jù)的準(zhǔn)確性。

如何分析數(shù)據(jù)庫(kù)樂(lè)觀鎖、悲觀鎖  
圖片來(lái)源于網(wǎng)絡(luò)

以上的圖就表示了并發(fā)場(chǎng)景時(shí),在沒(méi)有鎖機(jī)制的情況下,產(chǎn)生不正確的數(shù)據(jù),與預(yù)期的數(shù)據(jù)并不符合。實(shí)現(xiàn)并發(fā)控制的主要手段大致可以悲觀鎖和樂(lè)觀鎖。無(wú)論是悲觀鎖還是樂(lè)觀鎖,都是人們定義出來(lái)的概念,可以認(rèn)為是一種思想。    

悲觀鎖

當(dāng)我們要對(duì)一個(gè)數(shù)據(jù)庫(kù)中的一條數(shù)據(jù)進(jìn)行修改的時(shí)候,為了避免同時(shí)被其他人修改,最好的辦法就是直接對(duì)該數(shù)據(jù)進(jìn)行加鎖以防止并發(fā)。這種借助數(shù)據(jù)庫(kù)鎖機(jī)制,在修改數(shù)據(jù)之前先鎖定,再修改的方式被稱(chēng)之為悲觀并發(fā)控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫(xiě)“PCC”)。

這樣別的線程讀取該數(shù)據(jù)的時(shí)候就需要等待當(dāng)前線程釋放鎖,獲得到鎖的線程才能獲得該數(shù)據(jù)的讀寫(xiě)權(quán)限。從而保證了并發(fā)修改數(shù)據(jù)錯(cuò)誤的問(wèn)題。但是由于阻塞原因,所以導(dǎo)致吞吐量不高。悲觀鎖更適用于多寫(xiě)少讀的情況。


當(dāng)某一天,你的好友A說(shuō)要給你轉(zhuǎn)賬1000塊,好友B又說(shuō)給你轉(zhuǎn)賬1000塊。啥?天上掉餡餅了嗎?他們進(jìn)行了下面的操作:

 
  1. 好友A和好友B同時(shí)來(lái)到銀行,首先好友A獲取到你的余額為0,太窮了。

  2. 好友B此時(shí)獲取不到你的余額,因此好友B處于阻塞狀態(tài),等待ing…….。

  3. 好友A給你的銀行賬號(hào)里面匯入1000塊,總額等于money=money+1000。

  4. 好友A操作完,此時(shí)好友B獲取到你的余額1000塊,然后執(zhí)行轉(zhuǎn)賬操作money=money+1000,最后你的余額為2000。

假設(shè)轉(zhuǎn)賬的過(guò)程沒(méi)有鎖機(jī)制

  1. 好友A和好友B同時(shí)來(lái)到銀行,首先好友A獲取到你的余額為0,太窮了。

  2. 好友B此時(shí)也獲取到你的余額為0,然后給你轉(zhuǎn)賬1000,總額度變?yōu)?+1000=1000。

  3. 好友A也給你轉(zhuǎn)賬1000,總額度變?yōu)檫€是為1000,這結(jié)果肯定是不對(duì)的。

悲觀鎖,正如其名,它指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù),以及來(lái)自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度(悲觀),因此,在整個(gè)數(shù)據(jù)處理過(guò)程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制 (也只有數(shù)據(jù)庫(kù)層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問(wèn)的排他性,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無(wú)法保證外部系統(tǒng)不會(huì)修改數(shù)據(jù))。

即使使用了悲觀鎖,還是存在問(wèn)題,由于悲觀鎖使所有的訪問(wèn)者同步進(jìn)行,大量的訪問(wèn)就會(huì)阻塞,占用系統(tǒng)資源,最后的結(jié)果不可料想。此時(shí)樂(lè)觀鎖的作用就誕生了。

數(shù)據(jù)庫(kù)中,在對(duì)任意記錄進(jìn)行修改前,先嘗試為該記錄加上排他鎖(exclusive locking)。如果加鎖失敗,說(shuō)明該記錄正在被修改,那么當(dāng)前查詢(xún)可能要等待或者拋出異常。具體響應(yīng)方式由開(kāi)發(fā)者根據(jù)實(shí)際需要決定。如果成功加鎖,那么就可以對(duì)記錄做修改,事務(wù)完成后就會(huì)解鎖了。其間如果有其他對(duì)該記錄做修改或加排他鎖的操作,都會(huì)等待我們解鎖或直接拋出異常。

拿比較常用的MySql Innodb引擎舉例,來(lái)說(shuō)明一下在SQL中如何使用悲觀鎖。要使用悲觀鎖,我們必須關(guān)閉MySQL數(shù)據(jù)庫(kù)的自動(dòng)提交屬性。因?yàn)镸ySQL默認(rèn)使用autocommit模式(自動(dòng)提交事務(wù)),也就是說(shuō),當(dāng)我們執(zhí)行一個(gè)更新操作后,MySQL會(huì)立刻將結(jié)果進(jìn)行提交。

sql語(yǔ)句:set autocommit=0
 

以網(wǎng)購(gòu)扣減庫(kù)存來(lái)說(shuō)明一下悲觀鎖的使用:

//開(kāi)啟事務(wù)
begin;
select quantity from goods where id=1 for update;
update goods set quantity=2 where id =1;
//提交事務(wù)
commit;
 

以上,在對(duì)id = 1的記錄修改前,先通過(guò)for update的方式進(jìn)行加鎖,然后再進(jìn)行修改。如果以上修改庫(kù)存的代碼發(fā)生并發(fā),同一時(shí)間只有一個(gè)線程可以開(kāi)啟事務(wù)并獲得id=1的鎖,其它的事務(wù)必須等本次事務(wù)提交之后才能執(zhí)行。這樣我們可以保證當(dāng)前的數(shù)據(jù)不會(huì)被其它事務(wù)修改。

上面我們提到,使用select…for update會(huì)把數(shù)據(jù)給鎖住,不過(guò)我們需要注意一些鎖的級(jí)別,MySQL InnoDB默認(rèn)行級(jí)鎖。行級(jí)鎖都是基于索引的,如果一條SQL語(yǔ)句用不到索引是不會(huì)使用行級(jí)鎖的,會(huì)使用表鎖。

 

樂(lè)觀鎖

樂(lè)觀鎖( Optimistic Locking ) 相對(duì)悲觀鎖而言,樂(lè)觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會(huì)造成沖突,所以在數(shù)據(jù)進(jìn)行提交更新的時(shí)候,才會(huì)正式對(duì)數(shù)據(jù)的沖突與否進(jìn)行檢測(cè),如果發(fā)現(xiàn)沖突了,則讓返回用戶(hù)錯(cuò)誤的信息,讓用戶(hù)決定如何去做。由于樂(lè)觀鎖沒(méi)有了鎖等待,提高了吞吐量,所以樂(lè)觀鎖適合多讀少寫(xiě)的場(chǎng)景。 常見(jiàn)的樂(lè)觀鎖實(shí)現(xiàn)方式是:版本號(hào)versionCAS。

采用上面的例子,使用樂(lè)觀鎖加版本號(hào)的方式,給數(shù)據(jù)庫(kù)的表增加一個(gè)字段version版本號(hào),執(zhí)行的操作如下:

  • 你的好友A獲取你的余額為0并獲取當(dāng)前的版本號(hào)version=0。

  • 好友B也同時(shí)獲取你的余額為0并獲取當(dāng)前的版本號(hào)version=0。

  • 好好友A轉(zhuǎn)賬后的總額為1000,并使版本號(hào)version+1=1。更新到數(shù)據(jù)庫(kù)中。

  • 好友B同時(shí)也將金額1000匯進(jìn)你的賬號(hào)中,并使版本號(hào)version+1=1,提交事務(wù)的時(shí)候,發(fā)現(xiàn)版本號(hào)已被修改,提交事務(wù)失敗,更新不成功。

  • 此時(shí)好友B需要再次執(zhí)行轉(zhuǎn)賬操作,才能給你轉(zhuǎn)賬成功。

相對(duì)于悲觀鎖,在對(duì)數(shù)據(jù)庫(kù)進(jìn)行處理的時(shí)候,樂(lè)觀鎖并不會(huì)使用數(shù)據(jù)庫(kù)提供的鎖機(jī)制。一般的實(shí)現(xiàn)樂(lè)觀鎖的方式就是記錄數(shù)據(jù)版本。數(shù)據(jù)版本,為數(shù)據(jù)增加的一個(gè)版本標(biāo)識(shí)。當(dāng)讀取數(shù)據(jù)時(shí),將版本標(biāo)識(shí)的值一同讀出,數(shù)據(jù)每更新一次,同時(shí)對(duì)版本標(biāo)識(shí)進(jìn)行更新。當(dāng)我們提交更新的時(shí)候,判斷數(shù)據(jù)庫(kù)表對(duì)應(yīng)記錄的當(dāng)前版本信息與第一次取出來(lái)的版本標(biāo)識(shí)進(jìn)行比對(duì),如果數(shù)據(jù)庫(kù)表當(dāng)前版本號(hào)與第一次取出來(lái)的版本標(biāo)識(shí)值相等,則予以更新,否則認(rèn)為是過(guò)期數(shù)據(jù)。

使用樂(lè)觀鎖就不需要借助數(shù)據(jù)庫(kù)的鎖機(jī)制了。樂(lè)觀鎖的概念中其實(shí)已經(jīng)闡述了它的具體實(shí)現(xiàn)細(xì)節(jié)。主要就是兩個(gè)步驟:沖突檢測(cè)和數(shù)據(jù)更新。其實(shí)現(xiàn)方式有一種比較典型的就是CAS。

CAS是項(xiàng)樂(lè)觀鎖技術(shù),當(dāng)多個(gè)線程嘗試使用CAS同時(shí)更新同一個(gè)變量時(shí),只有其中一個(gè)線程能更新變量的值,而其它線程都失敗,失敗的線程并不會(huì)被掛起,而是被告知這次競(jìng)爭(zhēng)中失敗,并可以再次嘗試。

看完上述內(nèi)容,你們對(duì)如何分析數(shù)據(jù)庫(kù)樂(lè)觀鎖、悲觀鎖有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI