數(shù)據(jù)庫(kù)并發(fā)控制 你選樂(lè)觀鎖還是悲觀鎖?
實(shí)際生產(chǎn)環(huán)境里邊,如果并發(fā)量不大,完全可以使用悲觀鎖定的方法,這種方法使用起來(lái)非常方便和簡(jiǎn)單。但是如果系統(tǒng)的并發(fā)非常大的話,悲觀鎖定會(huì)帶來(lái)非常大的性能問(wèn)題,所以就要選擇樂(lè)觀鎖定的方法。
悲觀鎖假定其他用戶企圖訪問(wèn)或者改變你正在訪問(wèn)、更改的對(duì)象的概率是很高的,因此在悲觀鎖的環(huán)境中,在你開(kāi)始改變此對(duì)象之前就將該對(duì)象鎖住,并且直到你提交了所作的更改之后才釋放鎖。悲觀的缺陷是不論是頁(yè)鎖還是行鎖,加鎖的時(shí)間可能會(huì)很長(zhǎng),這樣可能會(huì)長(zhǎng)時(shí)間的限制其他用戶的訪問(wèn),也就是說(shuō)悲觀鎖的并發(fā)訪問(wèn)性不好。
樂(lè)觀鎖則認(rèn)為其他用戶企圖改變你正在更改的對(duì)象的概率是很小的,因此樂(lè)觀鎖直到你準(zhǔn)備提交所作的更改時(shí)才將對(duì)象鎖住,當(dāng)你讀取以及改變?cè)搶?duì)象時(shí)并不加鎖??梢?jiàn)樂(lè)觀鎖加鎖的時(shí)間要比悲觀鎖短,樂(lè)觀鎖可以用較大的鎖粒度獲得較好的并發(fā)訪問(wèn)性能。但是如果第二個(gè)用戶恰好在***個(gè)用戶提交更改之前讀取了該對(duì)象,那么當(dāng)他完成了自己的更改進(jìn)行提交時(shí),數(shù)據(jù)庫(kù)就會(huì)發(fā)現(xiàn)該對(duì)象已經(jīng)變化了,這樣,第二個(gè)用戶不得不重新讀取該對(duì)象并作出更改。這說(shuō)明在樂(lè)觀鎖環(huán)境中,會(huì)增加并發(fā)用戶讀取對(duì)象的次數(shù)。
以版本控制系統(tǒng)為例,來(lái)說(shuō)說(shuō)兩種最基本的并發(fā)性問(wèn)題。
【丟失更新】
小張想修改源代碼里面的a方法,正在她修改的同時(shí),小李打開(kāi)了這個(gè)文件,修改了b方法并且保存了文件,等小張修改完成后,保存文件,小李所做的修改就被覆蓋了。
【不一致的讀】
小張想要知道包里面一共有多少個(gè)類,包分了a,b兩個(gè)子包。小張打開(kāi)a包,看到了7個(gè)類。突然小張接到老婆打來(lái)的電話,在小張接電話的時(shí)候,小李往a包中加了2個(gè)類,b包中加了3個(gè)類(原先b包中是5個(gè)類)。
小張接完電話后再打開(kāi)b包,看到了8個(gè)類,很自然得出結(jié)論:包中一共有15個(gè)類。
很遺憾,15個(gè)永遠(yuǎn)不是正確的答案。在小李修改前,正確答案是12(7+5),修改后是17(9+8)。這兩個(gè)答案都是正確的,雖然有一個(gè)不是當(dāng)前的。但15不對(duì),因?yàn)樾堊x取的數(shù)據(jù)是不一致的。
小結(jié):不一致讀指你要讀取兩種數(shù)據(jù),這兩種數(shù)據(jù)都是正確的,但是在同一時(shí)刻兩者并非都正確。
【隔離 和 不可變】
在企業(yè)應(yīng)用中,解決并發(fā)沖突的兩種常用手段是隔離和不可變。
只有當(dāng)多個(gè)活動(dòng)(進(jìn)程或者線程)同時(shí)訪問(wèn)同一數(shù)據(jù)時(shí)才會(huì)引發(fā)并發(fā)問(wèn)題。一種很自然的思路就是同一時(shí)刻只允許一個(gè)活動(dòng)訪問(wèn)數(shù)據(jù)。如果小張打開(kāi)了文件,就不允許其他人打開(kāi),或者其他人只能通過(guò)只讀的方式打開(kāi)副本,就可以解決這個(gè)問(wèn)題。
隔離能夠有效減少發(fā)生錯(cuò)誤的可能。我們經(jīng)常見(jiàn)到程序員陷入到并發(fā)問(wèn)題的泥潭里,每一段代碼寫(xiě)完都要考慮并發(fā)問(wèn)題,這樣太累了。我們可以利用隔離技術(shù)創(chuàng)建出隔離區(qū)域,當(dāng)程序進(jìn)入隔離區(qū)域時(shí)不用關(guān)心并發(fā)問(wèn)題。好的并發(fā)性設(shè)計(jì)就是創(chuàng)造這樣的一些隔離區(qū)域,并保證代碼盡可能的運(yùn)行在其中。
另一種思路:只有當(dāng)你需要修改共享的數(shù)據(jù)時(shí)才可能引發(fā)并發(fā)性問(wèn)題,所以我們可以將要共享的數(shù)據(jù)制作為“不可變”的,以避免并發(fā)性問(wèn)題。當(dāng)然我們不可能將所有的數(shù)據(jù)都做成不可變的,但如果一些數(shù)據(jù)是不可變的,對(duì)它們進(jìn)行并發(fā)操作時(shí)我們就可以放松自己的神經(jīng)了。
【樂(lè)觀并發(fā)控制、悲觀并發(fā)控制】
如果數(shù)據(jù)是可變的,并且無(wú)法隔離呢?這種情況下最常用的兩種控制就是樂(lè)觀并發(fā)控制和悲觀并發(fā)控制。
假設(shè)小張和小李想要同時(shí)修改同一個(gè)文件。如果使用樂(lè)觀鎖,倆人都能打開(kāi)文件進(jìn)行修改,如果小張先提交了內(nèi)容,沒(méi)有問(wèn)題,他所做的改變會(huì)保存到服務(wù)器上。但小李提交時(shí)就會(huì)遇到麻煩,版本控制服務(wù)器會(huì)檢測(cè)出兩種修改的沖突,小李的提交會(huì)被具體,并由小李決定該如何處理這種情況(對(duì)于絕大部分版本控制軟件來(lái)說(shuō),會(huì)讀取并標(biāo)識(shí)出小張做的改變,然后由小李決定是否合并)。
如果使用的是悲觀鎖,小張先檢出(check out)文件,那么小李就無(wú)法再次檢出同一文件,直到小張?zhí)峤涣怂母淖儭?/p>
建議你將樂(lè)觀鎖想成一種檢測(cè)沖突的手段,而悲觀鎖是一種避免沖突的手段(嚴(yán)格來(lái)說(shuō),樂(lè)觀鎖其實(shí)不能稱之為“鎖”,但是這個(gè)名字已經(jīng)流傳開(kāi)了,那就繼續(xù)使用吧)。一些老的版本控制系統(tǒng),比如VSS 6.0使用的是悲觀鎖的機(jī)制。而現(xiàn)代的版本控制系統(tǒng)一般兩種都支持,默認(rèn)使用樂(lè)觀鎖。
兩種鎖各有優(yōu)缺點(diǎn)。。。這段懶的翻譯了,很明顯看出,樂(lè)觀鎖可以提高并發(fā)訪問(wèn)的效率,但是如果出現(xiàn)了沖突只能向上拋出,然后重來(lái)一遍;悲觀鎖可以避免沖突的發(fā)生,但是會(huì)降低效率。
選擇使用那一種鎖取決于訪問(wèn)頻率和一旦產(chǎn)生沖突的嚴(yán)重性。如果系統(tǒng)被并發(fā)訪問(wèn)的概率很低,或者沖突發(fā)生后的后果不太嚴(yán)重(所謂后果應(yīng)該指被檢測(cè)到?jīng)_突的提交會(huì)失敗,必須重來(lái)一次),可以使用樂(lè)觀鎖,否則使用悲觀鎖。
【我再補(bǔ)充兩句】我們經(jīng)常會(huì)在訪問(wèn)數(shù)據(jù)庫(kù)的時(shí)候用到鎖,怎么實(shí)現(xiàn)樂(lè)觀鎖和悲觀鎖呢?以Hibernate為例,可以通過(guò)為記錄添加版本或時(shí)間戳字段來(lái)實(shí)現(xiàn)樂(lè)觀鎖??梢杂胹ession.Lock()鎖定對(duì)象來(lái)實(shí)現(xiàn)悲觀鎖(本質(zhì)上就是執(zhí)行了SELECT * FROM t FOR UPDATE語(yǔ)句)。
另一個(gè)高并發(fā)控制解決方案樂(lè)觀并發(fā)控制和悲觀并發(fā)控制總結(jié)概述:
我們可以使用兩種形式的并發(fā)控制策略:樂(lè)觀并發(fā)控制和悲觀并發(fā)控制。
假設(shè)martin和David同時(shí)都要編輯Customer文件。如果使用樂(lè)觀鎖策略,他們兩個(gè)人都能得到一份文件的Copy,并且
可以自由編輯文件。假設(shè)David***個(gè)完成了工作,那么他可以毫無(wú)困難地更新他的修改。但是,當(dāng)Martin想要提交他的修改時(shí),并發(fā)控制策略就會(huì)開(kāi)始起作用。源代碼控制系統(tǒng)會(huì)檢測(cè)到在Martin的修改與David的修改之間存在著沖突,因而拒絕Martin的提交,并由Martin負(fù)責(zé)指出怎樣處理這種情況。如果使用悲觀鎖策略,只要有人先取出文件,其他人就不能對(duì)該文件進(jìn)行編輯。因此,假如是Martin先取了文件,那么David就只能在Martin完成任務(wù)并提交之后才能對(duì)該文件進(jìn)行操作。
如果把樂(lè)觀鎖看作是關(guān)于沖突檢測(cè)的,那么悲觀鎖就是關(guān)于沖突避免的。在實(shí)際應(yīng)用的源代碼控制系統(tǒng)中,
這兩種策略都可以被使用,但是現(xiàn)在大多數(shù)源代碼開(kāi)發(fā)者更傾向于使用樂(lè)觀鎖策略。(有一種很有道理的說(shuō)法:樂(lè)觀鎖并不是真正的鎖定,但是這種叫法很方便并且廣泛流傳,以至于不容忽略。)
這兩種策略各有優(yōu)缺點(diǎn)。悲觀鎖的問(wèn)題是減少了并發(fā)的程序。當(dāng)Martin正對(duì)一個(gè)被他加鎖的文件進(jìn)行編輯的時(shí)候,
其它人只能等著。使用過(guò)悲觀的源代碼控制人都知道這是一種多么令人喪氣的事情。對(duì)于企業(yè)數(shù)據(jù),情況經(jīng)常會(huì)變得更加糟糕,只要有人在編輯,其他人就無(wú)法進(jìn)行讀取,更加說(shuō)進(jìn)行編輯了。
樂(lè)觀鎖策略則允許人們更自由一些,因?yàn)橹挥性谔峤坏臅r(shí)候才有可能遇到阻礙。該策略的問(wèn)題在于當(dāng)沖突的時(shí)候會(huì)發(fā)生什么樣的事情呢?事實(shí)上,David之后的所有人在提交的時(shí)候都必須讀取David修改過(guò)的那個(gè)版本,并指出怎樣合并自己和David的修改,然后再提交一個(gè)重新修改過(guò)的***版本。有了源代碼控制系統(tǒng),這樣做并不會(huì)有什么麻煩。在許多場(chǎng)合下,源代碼控制系統(tǒng)確實(shí)能夠自動(dòng)進(jìn)行合并操作,甚至在無(wú)法自動(dòng)合并的時(shí)候,也能讓使用都很容易看出不同文件版本之間的差別。但是,業(yè)務(wù)數(shù)據(jù)通常都是很難被自動(dòng)合并的,所以經(jīng)常只能扔掉原來(lái)的東西,然后從頭開(kāi)始。
在樂(lè)觀鎖和悲觀鎖之間進(jìn)行選擇的標(biāo)準(zhǔn)是:沖突的頻率與嚴(yán)重性。如果沖突很少,或者沖突的后果不會(huì)很嚴(yán)重,那么通常情況下應(yīng)該選擇樂(lè)觀鎖,因?yàn)樗艿玫礁玫牟l(fā)性,而且更容易實(shí)現(xiàn)。但是,如果沖突的結(jié)果對(duì)于用戶來(lái)說(shuō)痛苦的,那么就需要使用悲觀策略。
樂(lè)觀鎖的局限是:只能在提交數(shù)據(jù)時(shí)才發(fā)現(xiàn)業(yè)務(wù)事務(wù)將要失敗,而且在某些情況下,發(fā)現(xiàn)失敗太遲的代價(jià)會(huì)很大。用戶可能花了一個(gè)小時(shí)的時(shí)間輸入一份租約的詳細(xì)信息,錯(cuò)誤太多會(huì)讓用戶對(duì)系統(tǒng)失去信心。另一個(gè)方法是使用悲觀鎖,它可以盡早地發(fā)現(xiàn)錯(cuò)誤,但理難以編程實(shí)現(xiàn),而且會(huì)降低系統(tǒng)的靈活性。
(注:以上是對(duì)并發(fā)控制中的樂(lè)觀鎖策略和悲觀鎖策略概念及解決思路的文字描述,下面我將對(duì)項(xiàng)目中具體怎么實(shí)現(xiàn)樂(lè)觀鎖策略及悲觀鎖策略進(jìn)行描述。)
樂(lè)觀鎖策略實(shí)現(xiàn)方法:
就是用C#中或SQL中的事務(wù)來(lái)實(shí)現(xiàn)數(shù)據(jù)操作不成功就回滾,個(gè)人感覺(jué)火車站賣票系統(tǒng)也是這樣操作的,我們看到顯示屏上有少量剩余票,但我們?nèi)ベI又打不出來(lái)。
悲觀鎖策略實(shí)現(xiàn)方法:
1、普通的aspx頁(yè)面,當(dāng)用戶點(diǎn)提交后,直接將提交及相關(guān)按鈕的enabel改為false,直到提交事件完成后,再改回來(lái)。另外在數(shù)據(jù)層那一塊,每次提交數(shù)據(jù)更改時(shí),都需要判斷數(shù)據(jù)以前的狀態(tài)是否改變,以防止有并發(fā)改變的情況出現(xiàn)。
2、jquery中,在jquery中,可以設(shè)置一個(gè)全局變量,提交時(shí),先判斷全局變量狀態(tài),如不允許提交則直接返回,如允許提交時(shí),則先將全局變量置為“不允許提交”,后開(kāi)始提交,提交完成后,在jquery的post方法的callback方法中,再將全局變量改為“允許提交”。
3、彈出式窗口修改頁(yè)面,則用模態(tài)方式彈出,如web頁(yè)面中,可用window.showModalDialog()來(lái)實(shí)現(xiàn)模態(tài)方式打開(kāi)修改頁(yè)面,來(lái)確保始終只有一個(gè)修改頁(yè)面被打開(kāi)。(這是從數(shù)據(jù)操作頁(yè)面處就悲觀鎖定了數(shù)據(jù),而不是在數(shù)據(jù)庫(kù)里面悲觀鎖定)
原文標(biāo)題:在數(shù)據(jù)庫(kù)中,并發(fā)控制有樂(lè)觀鎖和悲觀鎖之間,什么時(shí)候用樂(lè)觀鎖比較好什么時(shí)候用悲觀鎖比較好?
鏈接:http://www.cnblogs.com/chenlulouis/archive/2010/08/17/1801358.html
【編輯推薦】
- MySQL數(shù)據(jù)庫(kù)鎖機(jī)制的原理淺析
- MySQL鎖定機(jī)制的原理
- 使用調(diào)度和鎖定進(jìn)行MySQL查詢優(yōu)化
- MySQL數(shù)據(jù)庫(kù)表里如何進(jìn)行鎖定?
- MySQL表級(jí)鎖,行級(jí)鎖,頁(yè)級(jí)鎖各顯神通