本篇內(nèi)容介紹了“怎么理解Java悲觀鎖與樂(lè)觀鎖”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括謝家集網(wǎng)站建設(shè)、謝家集網(wǎng)站制作、謝家集網(wǎng)頁(yè)制作以及謝家集網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,謝家集網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到謝家集省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!1
鎖(Lock)
在介紹悲觀鎖和樂(lè)觀鎖之前,讓我們看一下什么是鎖。
鎖,在我們生活中隨處可見(jià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)祟愐环N消極的情緒,對(duì)應(yīng)到鎖的悲觀情緒,悲觀鎖認(rèn)為被它保護(hù)的數(shù)據(jù)是極其不安全的,每時(shí)每刻都有可能變動(dòng),一個(gè)事務(wù)拿到悲觀鎖后(可以理解為一個(gè)用戶),其他任何事務(wù)都不能對(duì)該數(shù)據(jù)進(jìn)行修改,只能等待鎖被釋放才可以執(zhí)行。
數(shù)據(jù)庫(kù)中的行鎖,表鎖,讀鎖,寫鎖,以及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)祟愐环N積極的情緒。樂(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)站,并且找到了同一家賣豬肉脯的>店鋪。下面是這個(gè)店鋪的商品表goods結(jié)構(gòu)和表中的數(shù)據(jù)。
從表中可以看到豬肉脯目前的數(shù)量只有1個(gè)了。在不加鎖的情況下,如果A,B同時(shí)下單,就有可能導(dǎo)致超賣。
悲觀鎖解決
利用悲觀鎖的解決思路是,我們認(rèn)為數(shù)據(jù)修改產(chǎn)生沖突的概率比較大,所以在更新之前,我們顯示的對(duì)要修改的記錄進(jìn)行加鎖,直到自己修改完再釋放鎖。加鎖期間只有自己可以進(jìn)行讀寫,其他事務(wù)只能讀不能寫。
A下單前先給豬肉脯這行數(shù)據(jù)(id=1)加上悲觀鎖(行鎖)。此時(shí)這行數(shù)據(jù)只能A來(lái)操作,也就是只有A能買。B想買就必須一直等待。
當(dāng)A買好后,B再想去買的時(shí)候會(huì)發(fā)現(xiàn)數(shù)量已經(jīng)為0,那么B看到后就會(huì)放棄購(gòu)買。
那么如何給豬肉脯也就是id=1這條數(shù)據(jù)加上悲觀鎖鎖呢?我們可以通過(guò)以下語(yǔ)句給id=1的這行數(shù)據(jù)加上悲觀鎖
select num from goods where id = 1 for update;
“怎么理解Java悲觀鎖與樂(lè)觀鎖”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!