高并发与锁
DRP學(xué)習(xí)中,我們對(duì)可能引起并發(fā)操作的情況使用了鎖,這次先理論上看看并發(fā)控制與鎖的一些內(nèi)容吧。
? ??并發(fā)控制
? ? 在多用戶環(huán)境中,在同一時(shí)間可能會(huì)有多個(gè)用戶更新相同的記錄,這會(huì)產(chǎn)生沖突。這就是并發(fā)性。典型的沖突有:
? ? 1、丟失更新(Lost updates)
? ? 一個(gè)事務(wù)的更新覆蓋了其它事務(wù)的更新結(jié)果,就是所謂的更新丟失。例如:用戶A把值從6改為2,用戶B把值從2改為6,則用戶A丟失了他的更新。
? ? 2、臟讀(Dirty reads)
? ? 當(dāng)一個(gè)事務(wù)讀取其它完成一半事務(wù)的記錄時(shí),就會(huì)發(fā)生臟讀取。例如:用戶A,B看到的值都是6,用戶B把值改為2,用戶A讀到的值仍為6。
? ? 3、不可重復(fù)讀(Non-repeatable reads)
? ? 當(dāng)一個(gè)進(jìn)程讀取了一筆數(shù)據(jù)后,另一個(gè)進(jìn)程更新了同一筆數(shù)據(jù),然后第一個(gè)進(jìn)程再次讀取同一筆數(shù)據(jù),卻得到了 與第一次讀取不同的結(jié)果。
? ? 在事務(wù)A更新記錄之后(update Customers set Name = 'B' where Name = 'A'),事務(wù)B讀取相同記錄(select Name form Customers where Name = 'A'),但事務(wù)B拿到的是事務(wù)A更新之后的數(shù)據(jù)(Customers.Name的值為'B'),在事務(wù)B讀取記錄之后,事務(wù)A進(jìn)行了事務(wù)回滾(Customers.Name的值為'A'),導(dǎo)致事務(wù)B的數(shù)據(jù)是不真實(shí)的。
? ??4、幻讀(Phantoms)
? ? 幻讀與臟讀的相似之處在于:兩者都是兩次讀取的結(jié)果不一致。
不同之處在于:幻讀是兩次讀取的記錄數(shù)量不一致,而臟讀是兩次讀取的記錄的數(shù)據(jù)不一致。
事務(wù)A讀取記錄之后(select * from Customers where Name like 'A%'),事務(wù)B又插入了符合事務(wù)A讀取條件的新記錄(insert into Customers(Name) values('AAA')),那么當(dāng)事務(wù)A再用相同條件讀取記錄時(shí),得到的集合卻與上一次讀取不同(多了記錄)。
? ?解決方案:線程同步和加鎖
? ?通常我們解決并發(fā)問題使用同步和加鎖兩種方式。
? ?同步中,我們通過Java中的synchronized關(guān)鍵字來實(shí)現(xiàn),但這樣通常會(huì)帶來性能和效率上的一些問題。
? ?這次,我們主要講解鎖。鎖機(jī)制中,我們可以根據(jù)不同情況使用悲觀鎖或樂觀鎖。
? ?悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
? ?對(duì)于悲觀鎖,我們可以提供一個(gè)值作為鎖的參數(shù)。比如一個(gè)鍵默認(rèn)會(huì)被鎖定15秒。15秒過后,如果你還沒有手動(dòng)的釋放鎖,那么使程序自動(dòng)的為你釋放。
? ?悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制(也只有數(shù)據(jù)庫(kù)層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制,也無法保證外部系統(tǒng)不會(huì)修改數(shù)據(jù))。但隨之而來的就是數(shù)據(jù)庫(kù)性能的大量開銷,特別是對(duì)長(zhǎng)事務(wù)而言,這樣的開銷往往無法承受。
? ?與之對(duì)應(yīng)的--樂觀鎖:
? ?樂觀鎖(Optimistic Lock), 就是很樂觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù)。
? ?而樂觀鎖機(jī)制在一定程度上解決了數(shù)據(jù)庫(kù)性能開銷這個(gè)問題。它大多是基于數(shù)據(jù)版本( Version )記錄機(jī)制實(shí)現(xiàn)。
? ?可以使用版本號(hào)、時(shí)間戳等機(jī)制。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫(kù)如果提供類似于write_condition機(jī)制的其實(shí)都是提供的樂觀鎖。比較
? ?1、兩種鎖各有優(yōu)缺點(diǎn),不可認(rèn)為一種好于另一種,像樂觀鎖適用于寫比較少的情況下,即沖突真的很少發(fā)生的時(shí)候,這樣可以省去了鎖的開銷,加大了系統(tǒng)的整個(gè)吞吐量。但如果經(jīng)常產(chǎn)生沖突,上層應(yīng)用會(huì)不斷的進(jìn)行retry,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。
? ?2、悲觀鎖和樂觀鎖最大的區(qū)別是是否一直鎖定資源,悲觀鎖在事物的全流程鎖定數(shù)據(jù),樂觀鎖不鎖定數(shù)據(jù)(用讀寫鎖是阻塞事物,而用樂觀鎖則會(huì)導(dǎo)致回滾,這個(gè)是一種事物沖突后的不同鎖的表象)。
? ?3、悲觀鎖和樂觀鎖都是為了解決丟失更新問題或者是臟讀。悲觀鎖和樂觀鎖的重點(diǎn)就是是否在讀取記錄的時(shí)候直接上鎖。悲觀鎖的缺點(diǎn)很明顯,需要一個(gè)持續(xù)的數(shù)據(jù)庫(kù)連接,這在web應(yīng)用中已經(jīng)不適合了。
總結(jié)
- 上一篇: 如何查询工行信用卡账单日和还款日期
- 下一篇: 高并发与锁(二)