自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

圖文并茂的帶你徹底理解悲觀鎖與樂(lè)觀鎖

開(kāi)發(fā) 開(kāi)發(fā)工具
這是一篇介紹悲觀鎖和樂(lè)觀鎖的入門(mén)文章。旨在讓那些不了解悲觀鎖和樂(lè)觀鎖的小白們弄清楚什么是悲觀鎖,什么是樂(lè)觀鎖。不同于其他文章,本文會(huì)配上相應(yīng)的圖解讓大家更容易理解。通過(guò)該文,你會(huì)學(xué)習(xí)到如下的知識(shí)。

 這是一篇介紹悲觀鎖和樂(lè)觀鎖的入門(mén)文章。旨在讓那些不了解悲觀鎖和樂(lè)觀鎖的小白們弄清楚什么是悲觀鎖,什么是樂(lè)觀鎖。不同于其他文章,本文會(huì)配上相應(yīng)的圖解讓大家更容易理解。通過(guò)該文,你會(huì)學(xué)習(xí)到如下的知識(shí)。

[[264303]]

1.鎖(Lock)

在介紹悲觀鎖和樂(lè)觀鎖之前,讓我們看一下什么是鎖。

鎖,在我們生活中隨處可見(jiàn),我們的門(mén)上有鎖,我們存錢(qián)的保險(xiǎn)柜上有鎖,是用來(lái)保護(hù)我們財(cái)產(chǎn)安全的。

程序中也有鎖,當(dāng)多個(gè)線程修改共享變量時(shí),我們可以給修改操作上鎖(syncronized)。

當(dāng)多個(gè)用戶修改表中同一數(shù)據(jù)時(shí),我們可以給該行數(shù)據(jù)上鎖(行鎖)。因此,鎖其實(shí)是在并發(fā)下控制多個(gè)操作的順序執(zhí)行,以此來(lái)保證數(shù)據(jù)安全的變動(dòng)。

并且,鎖是一種保證數(shù)據(jù)安全的機(jī)制和手段,而并不是特定于某項(xiàng)技術(shù)的。悲觀鎖和樂(lè)觀鎖亦是如此。本篇介紹的悲觀鎖和樂(lè)觀鎖是基于數(shù)據(jù)庫(kù)層面的。

 

2.悲觀鎖

悲觀鎖(Pessimistic Concurrency Control),***眼看到它,相信每個(gè)人都會(huì)想到這是一個(gè)悲觀的鎖。沒(méi)錯(cuò),它就是一個(gè)悲觀的鎖。

那這個(gè)悲觀體現(xiàn)在什么地方呢?悲觀是我們?nèi)祟?lèi)一種消極的情緒,對(duì)應(yīng)到鎖的悲觀情緒,悲觀鎖認(rèn)為被它保護(hù)的數(shù)據(jù)是極其不安全的,每時(shí)每刻都有可能變動(dòng),一個(gè)事務(wù)拿到悲觀鎖后(可以理解為一個(gè)用戶),其他任何事務(wù)都不能對(duì)該數(shù)據(jù)進(jìn)行修改,只能等待鎖被釋放才可以執(zhí)行。

數(shù)據(jù)庫(kù)中的行鎖,表鎖,讀鎖,寫(xiě)鎖,以及syncronized實(shí)現(xiàn)的鎖均為悲觀鎖。

 

這里再介紹一下什么是數(shù)據(jù)庫(kù)的表鎖和行鎖,以免有的同學(xué)對(duì)后面悲觀鎖的實(shí)現(xiàn)看不明白。

我們經(jīng)常使用的數(shù)據(jù)庫(kù)是mysql,mysql中最常用的引擎是Innodb,Innodb默認(rèn)使用的是行鎖。而行鎖是基于索引的,因此要想加上行鎖,在加鎖時(shí)必須***索引,否則將使用表鎖。

 

3.樂(lè)觀鎖

與悲觀相對(duì)應(yīng),樂(lè)觀是我們?nèi)祟?lèi)一種積極的情緒。樂(lè)觀鎖(Optimistic Concurrency Control)的“樂(lè)觀情緒”體現(xiàn)在,它認(rèn)為數(shù)據(jù)的變動(dòng)不會(huì)太頻繁。因此,它允許多個(gè)事務(wù)同時(shí)對(duì)數(shù)據(jù)進(jìn)行變動(dòng)。

但是,樂(lè)觀不代表不負(fù)責(zé),那么怎么去負(fù)責(zé)多個(gè)事務(wù)順序?qū)?shù)據(jù)進(jìn)行修改呢?

樂(lè)觀鎖通常是通過(guò)在表中增加一個(gè)版本(version)或時(shí)間戳(timestamp)來(lái)實(shí)現(xiàn),其中,版本最為常用。

事務(wù)在從數(shù)據(jù)庫(kù)中取數(shù)據(jù)時(shí),會(huì)將該數(shù)據(jù)的版本也取出來(lái)(v1),當(dāng)事務(wù)對(duì)數(shù)據(jù)變動(dòng)完畢想要將其更新到表中時(shí),會(huì)將之前取出的版本v1與數(shù)據(jù)中***的版本v2相對(duì)比,如果v1=v2,那么說(shuō)明在數(shù)據(jù)變動(dòng)期間,沒(méi)有其他事務(wù)對(duì)數(shù)據(jù)進(jìn)行修改,此時(shí),就允許事務(wù)對(duì)表中的數(shù)據(jù)進(jìn)行修改,并且修改時(shí)version會(huì)加1,以此來(lái)表明數(shù)據(jù)已被變動(dòng)。

如果,v1不等于v2,那么說(shuō)明數(shù)據(jù)變動(dòng)期間,數(shù)據(jù)被其他事務(wù)改動(dòng)了,此時(shí)不允許數(shù)據(jù)更新到表中,一般的處理辦法是通知用戶讓其重新操作。不同于悲觀鎖,樂(lè)觀鎖是人為控制的。

 

4.如何實(shí)現(xiàn)

經(jīng)過(guò)上面的學(xué)習(xí),我們知道悲觀鎖和樂(lè)觀鎖是用來(lái)控制并發(fā)下數(shù)據(jù)的順序變動(dòng)問(wèn)題的。那么我們就模擬一個(gè)需要加鎖的場(chǎng)景,來(lái)看不加鎖會(huì)出什么問(wèn)題,并且怎么利用悲觀鎖和樂(lè)觀鎖去解決。

場(chǎng)景:A和B用戶最近都想吃豬肉脯,于是他們打開(kāi)了購(gòu)物網(wǎng)站,并且找到了同一家賣(mài)豬肉脯的>店鋪。下面是這個(gè)店鋪的商品表goods結(jié)構(gòu)和表中的數(shù)據(jù)。

從表中可以看到豬肉脯目前的數(shù)量只有1個(gè)了。在不加鎖的情況下,如果A,B同時(shí)下單,就有可能導(dǎo)致超賣(mài)。

悲觀鎖解決

利用悲觀鎖的解決思路是,我們認(rèn)為數(shù)據(jù)修改產(chǎn)生沖突的概率比較大,所以在更新之前,我們顯示的對(duì)要修改的記錄進(jìn)行加鎖,直到自己修改完再釋放鎖。加鎖期間只有自己可以進(jìn)行讀寫(xiě),其他事務(wù)只能讀不能寫(xiě)。

A下單前先給豬肉脯這行數(shù)據(jù)(id=1)加上悲觀鎖(行鎖)。此時(shí)這行數(shù)據(jù)只能A來(lái)操作,也就是只有A能買(mǎi)。B想買(mǎi)就必須一直等待。

當(dāng)A買(mǎi)好后,B再想去買(mǎi)的時(shí)候會(huì)發(fā)現(xiàn)數(shù)量已經(jīng)為0,那么B看到后就會(huì)放棄購(gòu)買(mǎi)。

那么如何給豬肉脯也就是id=1這條數(shù)據(jù)加上悲觀鎖鎖呢?我們可以通過(guò)以下語(yǔ)句給id=1的這行數(shù)據(jù)加上悲觀鎖

  1. select num from goods where id = 1 for update

下面是悲觀鎖的加鎖圖解

 

我們通過(guò)開(kāi)啟mysql的兩個(gè)會(huì)話,也就是兩個(gè)命令行來(lái)演示。

1、事務(wù)A執(zhí)行命令給id=1的數(shù)據(jù)上悲觀鎖準(zhǔn)備更新數(shù)據(jù)

 

這里之所以要以begin開(kāi)始,是因?yàn)閙ysql是自提交的,所以要以begin開(kāi)啟事務(wù),否則所有修改將被mysql自動(dòng)提交。

2、事務(wù)B也去給id=1的數(shù)據(jù)上悲觀鎖準(zhǔn)備更新數(shù)據(jù)

 

我們可以看到此時(shí)事務(wù)B再一直等待A釋放鎖。如果A長(zhǎng)期不釋放鎖,那么最終事務(wù)B將會(huì)報(bào)錯(cuò),這有興趣的可以去嘗試一下。

3、接著我們讓事務(wù)A執(zhí)行命令去修改數(shù)據(jù),讓豬肉脯的數(shù)量減一,然后查看修改后的數(shù)據(jù),***commit,結(jié)束事務(wù)。

 

我們可以看到,此時(shí)***一個(gè)豬肉脯被A買(mǎi)走,只剩0個(gè)了。

4、當(dāng)事務(wù)A執(zhí)行完第3步后,我們看事務(wù)B中出現(xiàn)了什么

 

我們看到由于事務(wù)A釋放了鎖,事務(wù)B就結(jié)束了等待,拿到了鎖,但是數(shù)據(jù)此時(shí)變成了0,那么B看到后就知道被買(mǎi)走了,就會(huì)放棄購(gòu)買(mǎi)。

通過(guò)悲觀鎖,我們解決了豬肉脯購(gòu)買(mǎi)的問(wèn)題。

樂(lè)觀鎖解決

下面,我們利用樂(lè)觀鎖來(lái)解決該問(wèn)題。上面樂(lè)觀鎖的介紹中,我們提到了,樂(lè)觀鎖是通過(guò)版本號(hào)version來(lái)實(shí)現(xiàn)的。所以,我們需要給goods表加上version字段,表變動(dòng)后的結(jié)構(gòu)如下:

使用樂(lè)觀鎖的解決思路是,我們認(rèn)為數(shù)據(jù)修改產(chǎn)生沖突的概率并不大,多個(gè)事務(wù)在修改數(shù)據(jù)的之前先查出版本號(hào),在修改時(shí)把當(dāng)前版本號(hào)作為修改條件,只會(huì)有一個(gè)事務(wù)可以修改成功,其他事務(wù)則會(huì)失敗。

A和B同時(shí)將豬肉脯(id=1下面都說(shuō)是id=1)的數(shù)據(jù)查出來(lái),然后A先買(mǎi),A將id=1和version=0作為條件進(jìn)行數(shù)據(jù)更新,即將數(shù)量-1,并且將版本號(hào)+1。

此時(shí)版本號(hào)變?yōu)?。A此時(shí)就完成了商品的購(gòu)買(mǎi)。***B開(kāi)始買(mǎi),B也將id=1和version=0作為條件進(jìn)行數(shù)據(jù)更新,但是更新完后,發(fā)現(xiàn)更新的數(shù)據(jù)行數(shù)為0,此時(shí)就說(shuō)明已經(jīng)有人改動(dòng)過(guò)數(shù)據(jù),此時(shí)就應(yīng)該提示用戶重新查看***數(shù)據(jù)購(gòu)買(mǎi)。

下面是樂(lè)觀鎖的加鎖圖解

 

我們還是通過(guò)開(kāi)啟mysql的兩個(gè)會(huì)話,也就是兩個(gè)命令行來(lái)演示。

1、事務(wù)A執(zhí)行查詢命令,事務(wù)B執(zhí)行查詢命令,因?yàn)閮烧卟樵兊慕Y(jié)果相同,所以下面我只列出一個(gè)截圖。

 

此時(shí)A和B均獲取到相同的數(shù)據(jù)

2、事務(wù)A進(jìn)行購(gòu)買(mǎi)更新數(shù)據(jù),然后再查詢更新后的數(shù)據(jù)。

 

我們可以看到事務(wù)A成功更新了數(shù)據(jù)和版本號(hào)。

事務(wù)B再進(jìn)行購(gòu)買(mǎi)更新數(shù)據(jù),然后我們看影響行數(shù)和更新后的數(shù)據(jù)

 

可以看到最終修改行數(shù)為0,數(shù)據(jù)沒(méi)有改變。此時(shí)就需要我們告知用戶重新處理。

5.優(yōu)缺點(diǎn)

下面我們介紹下樂(lè)觀鎖和悲觀鎖的優(yōu)缺點(diǎn)以便我們分析他們的應(yīng)用場(chǎng)景,這里我只分析最重要的優(yōu)缺點(diǎn),也是我們要記住的。

悲觀鎖

  • 優(yōu)點(diǎn):悲觀鎖利用數(shù)據(jù)庫(kù)中的鎖機(jī)制來(lái)實(shí)現(xiàn)數(shù)據(jù)變化的順序執(zhí)行,這是最有效的辦法
  • 缺點(diǎn):一個(gè)事務(wù)用悲觀鎖對(duì)數(shù)據(jù)加鎖之后,其他事務(wù)將不能對(duì)加鎖的數(shù)據(jù)進(jìn)行除了查詢以外的所有操作,如果該事務(wù)執(zhí)行時(shí)間很長(zhǎng),那么其他事務(wù)將一直等待,那勢(shì)必影響我們系統(tǒng)的吞吐量。

樂(lè)觀鎖

  • 優(yōu)點(diǎn):樂(lè)觀鎖不在數(shù)據(jù)庫(kù)上加鎖,任何事務(wù)都可以對(duì)數(shù)據(jù)進(jìn)行操作,在更新時(shí)才進(jìn)行校驗(yàn),這樣就避免了悲觀鎖造成的吞吐量下降的劣勢(shì)。
  • 缺點(diǎn):樂(lè)觀鎖因?yàn)槭峭ㄟ^(guò)我們?nèi)藶閷?shí)現(xiàn)的,它僅僅適用于我們自己業(yè)務(wù)中,如果有外來(lái)事務(wù)插入,那么就可能發(fā)生錯(cuò)誤。

6.應(yīng)用場(chǎng)景

悲觀鎖:因?yàn)楸^鎖會(huì)影響系統(tǒng)吞吐的性能,所以適合應(yīng)用在寫(xiě)為居多的場(chǎng)景下。

樂(lè)觀鎖:因?yàn)闃?lè)觀鎖就是為了避免悲觀鎖的弊端出現(xiàn)的,所以適合應(yīng)用在讀為居多的場(chǎng)景下。

參考資料

https://chenzhou123520.iteye.com/blog/1860954

https://baike.baidu.com/item/樂(lè)觀鎖/7146502

【本文是51CTO專欄作者Hollis的原創(chuàng)文章,作者微信公眾號(hào)Hollis(ID:hollischuang)】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來(lái)源: 51CTO專欄
相關(guān)推薦

2024-05-17 09:33:22

樂(lè)觀鎖CASversion

2024-07-25 09:01:22

2023-02-23 10:32:52

樂(lè)觀鎖

2021-03-30 09:45:11

悲觀鎖樂(lè)觀鎖Optimistic

2022-07-25 06:44:19

ZooKeeper分布式鎖

2024-01-29 01:08:01

悲觀鎖遞歸鎖讀寫(xiě)鎖

2024-09-03 15:14:42

2025-04-23 08:45:00

悲觀鎖樂(lè)觀鎖并發(fā)控制機(jī)制

2018-07-31 10:10:06

MySQLInnoDB死鎖

2011-08-18 13:44:42

Oracle悲觀鎖樂(lè)觀鎖

2023-07-05 08:18:54

Atomic類(lèi)樂(lè)觀鎖悲觀鎖

2020-09-04 09:20:59

Java開(kāi)發(fā)代碼

2019-04-19 09:48:53

樂(lè)觀鎖悲觀鎖數(shù)據(jù)庫(kù)

2019-11-28 16:00:06

重入鎖讀寫(xiě)鎖樂(lè)觀鎖

2009-09-25 16:43:44

Hibernate悲觀Hibernate樂(lè)觀

2019-01-04 11:18:35

獨(dú)享鎖共享鎖非公平鎖

2020-07-06 08:03:32

Java悲觀鎖樂(lè)觀鎖

2023-08-17 14:10:11

Java開(kāi)發(fā)前端

2020-09-16 07:56:28

多線程讀寫(xiě)鎖悲觀鎖

2011-01-18 18:08:28

Thunderbird
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)