??之前在(十三)事務(wù)處理中簡單的介紹了鎖系統(tǒng)陡蝇,并且介紹了由于并發(fā)而產(chǎn)生的種種問題,例如臟讀广匙、幻讀等,因此這里對如何解決這些問題再進(jìn)行一下補(bǔ)充潮剪。
1分唾、悲觀鎖
??在關(guān)系型數(shù)據(jù)庫管理系統(tǒng)里绽乔,悲觀并發(fā)控制是一種并發(fā)控制的方法,它可以阻止一個事務(wù)以影響其他事務(wù)的方式來修改數(shù)據(jù)看疗。悲觀鎖需要使用數(shù)據(jù)庫的鎖機(jī)制两芳,可以從字面理解為這種并發(fā)方式就是很悲觀去枷,每次調(diào)用數(shù)據(jù)的時候都認(rèn)為同時會有其他事務(wù)在修改數(shù)據(jù)是复,因此每次在調(diào)用數(shù)據(jù)前都會先上鎖淑廊,這樣可以防止其他事務(wù)讀取或修改表中的數(shù)據(jù)蒋纬。
??例如:

??此處之所以會出現(xiàn)死鎖坚弱,就是因為執(zhí)行這條語句時已經(jīng)使用了鎖荒叶,
UPDATE tbl_name SET col_name = newValue WHERE id = x;
??因此互相調(diào)用相同的字段造成了死鎖些楣。
??悲觀并發(fā)控制主要用于數(shù)據(jù)爭用激烈的環(huán)境,以及發(fā)生并發(fā)沖突時使用鎖保護(hù)數(shù)據(jù)的成本要低于回滾事務(wù)的成本的環(huán)境中蚕钦。悲觀并發(fā)控制實際上是”先取鎖再訪問”的保守策略鹅很,為數(shù)據(jù)處理的安全提供了保證促煮。但是在效率方面,處理加鎖的機(jī)制會讓數(shù)據(jù)庫產(chǎn)生額外的開銷佑吝,并且會增加產(chǎn)生死鎖的機(jī)會芋忿;另外疾棵,在只讀型事務(wù)處理中由于不會產(chǎn)生沖突,也沒必要使用鎖逆趣,這樣做只能增加系統(tǒng)負(fù)載嗜历,還會降低并行性抖所,因為一個事務(wù)如果鎖定了某行數(shù)據(jù)田轧,其他事務(wù)就必須等待該事務(wù)處理完才可以進(jìn)行處理傻粘。
2帮掉、樂觀鎖
??樂觀鎖相對于悲觀鎖而言,通常會假設(shè)多用戶并發(fā)的事務(wù)在處理時不會彼此互相影響稽莉,各事務(wù)能夠在不產(chǎn)生鎖的情況下處理各自負(fù)責(zé)的數(shù)據(jù)污秆。在提交數(shù)據(jù)更新之前良拼,每個事務(wù)會先檢查在讀取數(shù)據(jù)后充边,有無其他事務(wù)再次修改了該數(shù)據(jù)痛黎。如果有湖饱,那么當(dāng)前正在提交的事務(wù)會進(jìn)行回滾杀捻≈录ィ可以從字面理解為這種并發(fā)方式就是很樂觀垢袱,每次調(diào)用數(shù)據(jù)的時候都認(rèn)為其他事務(wù)不會在同時修改數(shù)據(jù)请契,因此不會上鎖夏醉。
??在處理數(shù)據(jù)時,樂觀鎖并不會使用數(shù)據(jù)庫提供的鎖機(jī)制臣樱,通常樂觀鎖的實現(xiàn)方式是記錄數(shù)據(jù)版本玄捕,即為數(shù)據(jù)增加一個版本標(biāo)識,一般是通過為數(shù)據(jù)庫表增加一個數(shù)字類型的 “version” 字段來實現(xiàn)席吴。當(dāng)讀取數(shù)據(jù)時,將version字段的值一同讀出柬姚,數(shù)據(jù)每更新一次量承,對此version值加1撕捍。當(dāng)提交更新的時候,判斷當(dāng)前version值是否與之前讀出的version值一致狮腿,如果相同缘厢,則予以更新贴硫,否則認(rèn)為是過期數(shù)據(jù)夜畴。
??例如:
??假設(shè)用戶A和用戶B對同一張數(shù)據(jù)表的同一個字段記錄值進(jìn)行修改贪绘,此時用戶A和用戶B從該表中讀取的version值為2均函,用戶A對記錄修改結(jié)束后菱涤,version值增加1如迟,此時該表的version字段的值是3,而用戶B依然按照version值為2進(jìn)行操作玲销,不滿足“提交版本必須大于記錄當(dāng)前版本才能執(zhí)行更新”的樂觀鎖策略贤斜,因此,用戶B的提交被駁回。這樣堕战,就避免了用戶B用基于version值為2的舊數(shù)據(jù)修改的結(jié)果覆蓋用戶A的操作結(jié)果的可能薪介。
??樂觀并發(fā)控制多數(shù)用于數(shù)據(jù)爭用不大道偷、沖突較少的環(huán)境中,此時偶爾回滾事務(wù)的成本會低于讀取數(shù)據(jù)時鎖定數(shù)據(jù)的成本并巍,因此可以獲得比其他并發(fā)控制方法更高的吞吐量换途。
3、MVCC
??多版本并發(fā)控制(Multi-Version Concurrency Control)是為了實現(xiàn)數(shù)據(jù)庫的并發(fā)控制而設(shè)計的一種機(jī)制剃执。大多數(shù)的關(guān)系型數(shù)據(jù)庫都支持MVCC懈息,其突出特點是:讀不加鎖肾档,讀寫不沖突辫继。
??在MVCC中,讀操作可以分成兩類骇两,快照讀和當(dāng)前讀:
- 快照讀,讀取的是記錄的可見版本(可能是歷史版本配阵,即最新的數(shù)據(jù)可能正在被當(dāng)前執(zhí)行的事務(wù)并發(fā)修改)示血,不會對返回的記錄加鎖;
- 當(dāng)前讀难审,讀取的是記錄的最新版本,并且會對返回的記錄加鎖黔姜,保證其他事務(wù)不會并發(fā)修改這條記錄。
??在MySQL InnoDB中泻拦,基本的SELECT操作陆错,如
SELECT * FROM tbl_name WHERE xxxx;
??都屬于快照讀绳慎;而屬于當(dāng)前讀的包含以下操作:
SELECT * FROM tbl_name WHERE xxxx LOCK IN SHARE MODE;(共享鎖)
SELECT * FROM tbl_name WHERE xxxx FOR UPDATE;(排他鎖)
INSERT珊楼,UPDATE,DELETE操作(排他鎖)
??可以將MVCC理解為行級鎖的一種妥協(xié)霹购,它在許多情況下避免了使用鎖,同時可以提供更小的開銷。根據(jù)實現(xiàn)的不同催训,它可以允許非阻塞式讀审胚,在寫操作進(jìn)行時只鎖定必要的記錄痘系。
??各個存儲引擎對于MVCC的實現(xiàn)各不相同复唤,下面將通過一個簡化的InnoDB版本的行為來展示MVCC工作原理:
簡單來說呈宇,通過為每一行記錄添加兩個額外的隱藏的值來實現(xiàn)MVCC,這兩個值一個記錄這行數(shù)據(jù)何時被創(chuàng)建,另外一個記錄這行數(shù)據(jù)何時過期(或者被刪除)。但是InnoDB并不存儲這些事件發(fā)生時的實際時間,相反它只存儲這些事件發(fā)生時的系統(tǒng)版本號。這是一個隨著事務(wù)的創(chuàng)建而不斷增長的數(shù)字昔馋。每個事務(wù)在事務(wù)開始時會記錄它自己的系統(tǒng)版本號垄提。每個查詢必須去檢查每行數(shù)據(jù)的版本號與事務(wù)的版本號是否相同审丘。
??以下是在默認(rèn)隔離級別REPEATABLE READ下脓钾,MVCC具體是怎樣實現(xiàn)的:
SELECT:
??InnoDB只查找版本早于(包含等于)當(dāng)前事務(wù)版本的數(shù)據(jù)行。這保證了不管是事務(wù)開始之前谨胞,或者事務(wù)創(chuàng)建時,或者修改了這行數(shù)據(jù)的時候辜伟,這行數(shù)據(jù)是存在的独郎;這行數(shù)據(jù)的刪除版本必須是未定義的或者比事務(wù)版本要大贪婉,這可以保證在事務(wù)開始之前這行數(shù)據(jù)沒有被刪除。
??符合這兩個條件的行可能會被當(dāng)作查詢結(jié)果而返回巩螃。INSERT:
InnoDB為這個新行記錄當(dāng)前的系統(tǒng)版本號歹叮。DELETE:
InnoDB將當(dāng)前的系統(tǒng)版本號設(shè)置為這一行的刪除ID。UPDATE:
InnoDB會寫一個這行數(shù)據(jù)的新拷貝吻商,這個拷貝的版本為當(dāng)前的系統(tǒng)版本號。它同時也會將這個版本號寫到舊行的刪除版本里阳藻。
4夹厌、MVCC與樂觀鎖的區(qū)別
??在了解了MVCC的實現(xiàn)機(jī)制后可能會感覺與樂觀鎖中使用版本號加鎖有相似之處,實際上MVCC可以保證不阻塞地讀到一致的數(shù)據(jù)权她。但是感局,MVCC并沒有對實現(xiàn)細(xì)節(jié)做約束藻雌,在InnoDB引擎下是只對讀無鎖做个,寫操作仍是上鎖的悲觀并發(fā)控制居暖,這也意味著莺奸,InnoDB中只能見到因死鎖和不變性約束而回滾,而不會出現(xiàn)因為寫沖突而回滾的現(xiàn)象略贮;MVCC對數(shù)據(jù)表中的每行數(shù)據(jù)只保留一份讽膏,在更新數(shù)據(jù)時上行級鎖,同時將舊版數(shù)據(jù)寫入undo log闷盔;數(shù)據(jù)表和undo log中行數(shù)據(jù)都記錄著事務(wù)ID迫皱,在檢索時戏阅,只讀取來自當(dāng)前已提交的事務(wù)的行數(shù)據(jù)。這種額外的記錄所帶來的結(jié)果就是對于大多數(shù)查詢來說根本就不需要獲得一個鎖舱痘。MVCC只是簡單地以最快的速度來讀取數(shù)據(jù)离赫,確保只選擇符合條件的行。但其缺點也正是存儲引擎必須為每一行存儲更多的數(shù)據(jù)渊胸,做更多的檢查工作,處理更多的善后操作翎猛。
版權(quán)聲明:歡迎轉(zhuǎn)載,歡迎擴(kuò)散办成,但轉(zhuǎn)載時請標(biāo)明作者以及原文出處搂漠,謝謝合作! ↓↓↓