數(shù)據(jù)庫鎖和數(shù)據(jù)庫隔離級(jí)別
最近突然發(fā)現(xiàn)忘了數(shù)據(jù)庫鎖和數(shù)據(jù)庫隔離級(jí)別,時(shí)常弄混它們之間的關(guān)系。為此特此寫下此博客,以方便自己復(fù)習(xí),同時(shí)也可以幫助博友。
數(shù)據(jù)庫鎖
數(shù)據(jù)庫鎖就是事務(wù)T在對(duì)某個(gè)數(shù)據(jù)對(duì)象(例如表、記錄等)操作之前,先向系統(tǒng)發(fā)出請(qǐng)求,對(duì)其加鎖。加鎖后事務(wù)T就對(duì)該數(shù)據(jù)對(duì)象有了一定的控制,在事務(wù)T釋放它的鎖之前,其它的事務(wù)不能更新此數(shù)據(jù)對(duì)象。
數(shù)據(jù)庫鎖是實(shí)現(xiàn)并發(fā)控制的重要技術(shù),但是“鎖”會(huì)帶來系統(tǒng)額外的開銷。所以需要注意選擇封鎖粒度時(shí)必須同時(shí)考慮開銷和并發(fā)度兩個(gè)因素,進(jìn)行權(quán)衡,以求得最優(yōu)的效果。
鎖的類型主要有兩種類型排它鎖(也叫獨(dú)占鎖)和共享鎖,當(dāng)然還有很多教程增加了一種--更新鎖。
共享(S)鎖:多個(gè)事務(wù)可封鎖一個(gè)共享頁;任何事務(wù)都不能修改該頁; 通常是該頁被讀取完畢,S鎖立即被釋放。在執(zhí)行select語句的時(shí)候需要給操作對(duì)象(表或者一些記錄)加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒有,則可以加共享鎖(一個(gè)對(duì)象上可以加n個(gè)共享鎖),否則不行。共享鎖通常在執(zhí)行完select語句之后被釋放,當(dāng)然也有可能是在事務(wù)結(jié)束(包括正常結(jié)束和異常結(jié)束)的時(shí)候被釋放,主要取決與數(shù)據(jù)庫所設(shè)置的事務(wù)隔離級(jí)別。
排它(X)鎖:僅允許一個(gè)事務(wù)封鎖此頁;其他任何事務(wù)必須等到X鎖被釋放才能對(duì)該頁進(jìn)行訪問;X鎖一直到事務(wù)結(jié)束才能被釋放。執(zhí)行insert、update、delete語句的時(shí)候需要給操作的對(duì)象加排他鎖(我感覺在執(zhí)行insert的時(shí)候應(yīng)該是在表級(jí)加排他鎖),在加排他鎖之前必須確認(rèn)該對(duì)象上沒有其他任何鎖,一旦加上排他鎖之后,就不能再給這個(gè)對(duì)象加其他任何鎖。排他鎖的釋放通常是在事務(wù)結(jié)束的時(shí)候(當(dāng)然也有例外,就是在數(shù)據(jù)庫事務(wù)隔離級(jí)別被設(shè)置成Read Uncommitted(讀未提交數(shù)據(jù))的時(shí)候,這種情況下排他鎖會(huì)在執(zhí)行完更新操作之后就釋放,而不是在事務(wù)結(jié)束的時(shí)候)。
更新(U)鎖:用來預(yù)定要對(duì)此頁施加X鎖,它允許其他事務(wù)讀,但不允許再施加U鎖或X鎖;當(dāng)被讀取的頁將要被更新時(shí),則升級(jí)為X鎖;U鎖一直到事務(wù)結(jié)束時(shí)才能被釋放。數(shù)據(jù)庫是支持在一個(gè)事務(wù)中進(jìn)行自動(dòng)鎖升級(jí)的,例如,在某個(gè)事務(wù)中先執(zhí)行select語句,后執(zhí)行update語句,這兩條語句操作了同一個(gè)對(duì)象,并且假定共享鎖是在事務(wù)結(jié)束的時(shí)候被釋放的。如果數(shù)據(jù)庫不支持自動(dòng)鎖升級(jí),那么當(dāng)update語句請(qǐng)求排他鎖的時(shí)候?qū)⒉荒艹晒ΑR驗(yàn)橹皊elect語句的共享鎖沒有被釋放,那么事務(wù)就進(jìn)入了無限等待,即死鎖。有了自動(dòng)鎖升級(jí),在執(zhí)行update語句的時(shí)候就可以將之前加的共享鎖升級(jí)為排他鎖,但有個(gè)前提,就是這個(gè)共享鎖必須是本事務(wù)自己加的,而且在操作對(duì)象上沒有在加其他任何鎖,否則共享鎖是不能被升級(jí)為排他鎖的,必須等待其他鎖的釋放。
因?yàn)橥ǔT趫?zhí)行更新操作的時(shí)候要先查詢,也就是我們通常會(huì)在update語句和delete語句中加where子句。那么,有的數(shù)據(jù)庫系統(tǒng)可能會(huì)在執(zhí)行查詢的時(shí)候先給操作對(duì)象加共享鎖,然后在更新的時(shí)候加排他鎖,但這么做會(huì)有問題,也就是如果兩個(gè)事務(wù)同時(shí)要更新一個(gè)對(duì)象,都先給這個(gè)對(duì)象加了共享鎖,當(dāng)要更新的時(shí)候,都請(qǐng)求升級(jí)鎖,但由于這個(gè)對(duì)象上存在對(duì)方事務(wù)加的共享鎖。。所以無法升級(jí)。這樣兩個(gè)事務(wù)就在等待對(duì)方釋放共享鎖,進(jìn)入死鎖狀態(tài)。更新鎖就是為了解決這個(gè)問題,即在執(zhí)行查詢操作的時(shí)候加的不是共享鎖而是更新鎖(一個(gè)對(duì)象上只能有一個(gè)更新鎖和n個(gè)共享鎖),當(dāng)要更新的時(shí)候,再將更新鎖升級(jí)為排他鎖,升級(jí)前提是這個(gè)對(duì)象上只有本事務(wù)加的更新鎖,沒有其他任何鎖了。其實(shí),,我想,如果在執(zhí)行查詢的時(shí)候就給事務(wù)加排他鎖不也能解決死鎖問題嗎,但這樣似乎會(huì)減弱系統(tǒng)的并發(fā)性能。
數(shù)據(jù)庫的事務(wù)隔離級(jí)別
在數(shù)據(jù)庫操作中,為了有效保證并發(fā)讀取數(shù)據(jù)的正確性,提出的事務(wù)隔離級(jí)別。
在沒有數(shù)據(jù)庫的事務(wù)隔離級(jí)別時(shí)會(huì)出現(xiàn)如下問題:
更新丟失
兩個(gè)事務(wù)都同時(shí)更新一行數(shù)據(jù),但是第二個(gè)事務(wù)卻中途失敗退出,導(dǎo)致對(duì)數(shù)據(jù)的兩個(gè)修改都失效了。這是因?yàn)橄到y(tǒng)沒有執(zhí)行任何的鎖操作,因此并發(fā)事務(wù)并沒有被隔離開來。
臟讀
一個(gè)事務(wù)開始讀取了某行數(shù)據(jù),但是另外一個(gè)事務(wù)已經(jīng)更新了此數(shù)據(jù)但沒有能夠及時(shí)提交。這是相當(dāng)危險(xiǎn)的,因?yàn)楹芸赡芩械牟僮鞫急换貪L。
不可重復(fù)讀
不可重復(fù)讀(Non-repeatable Reads):一個(gè)事務(wù)對(duì)同一行數(shù)據(jù)重復(fù)讀取兩次,但是卻得到了不同的結(jié)果。
包括以下情況:
(1) 事務(wù)T1讀取某一數(shù)據(jù)后,事務(wù)T2對(duì)其做了修改,當(dāng)事務(wù)T1再次讀該數(shù)據(jù)時(shí)得到與前一次不同的值。
(2) 幻讀(Phantom Reads):事務(wù)在操作過程中進(jìn)行兩次查詢,第二次查詢的結(jié)果包含了第一次查詢中未出現(xiàn)的數(shù)據(jù)或者缺少了第一次查詢中出現(xiàn)的數(shù)據(jù)(這里并不要求兩次查詢的SQL語句相同)。這是因?yàn)樵趦纱尾樵冞^程中有另外一個(gè)事務(wù)插入數(shù)據(jù)造成的。
為了避免上面出現(xiàn)的幾種情況,在標(biāo)準(zhǔn)SQL規(guī)范中,定義了4個(gè)事務(wù)隔離級(jí)別,不同的隔離級(jí)別對(duì)事務(wù)的處理不同。
未授權(quán)讀取
也稱為讀未提交(Read Uncommitted):允許臟讀取,但不允許更新丟失。如果一個(gè)事務(wù)已經(jīng)開始寫數(shù)據(jù),則另外一個(gè)事務(wù)則不允許同時(shí)進(jìn)行寫操作,但允許其他事務(wù)讀此行數(shù)據(jù)。該隔離級(jí)別可以通過“排他寫鎖”實(shí)現(xiàn)。
授權(quán)讀取
也稱為讀提交(Read Committed):允許不可重復(fù)讀取,但不允許臟讀取。這可以通過“瞬間共享讀鎖”和“排他寫鎖”實(shí)現(xiàn)。讀取數(shù)據(jù)的事務(wù)允許其他事務(wù)繼續(xù)訪問該行數(shù)據(jù),但是未提交的寫事務(wù)將會(huì)禁止其他事務(wù)訪問該行。
可重復(fù)讀取(Repeatable Read)
可重復(fù)讀取(Repeatable Read):禁止不可重復(fù)讀取和臟讀取,但是有時(shí)可能出現(xiàn)幻影數(shù)據(jù)。這可以通過“共享讀鎖”和“排他寫鎖”實(shí)現(xiàn)。讀取數(shù)據(jù)的事務(wù)將會(huì)禁止寫事務(wù)(但允許讀事務(wù)),寫事務(wù)則禁止任何其他事務(wù)。
序列化(Serializable)
序列化(Serializable):提供嚴(yán)格的事務(wù)隔離。它要求事務(wù)序列化執(zhí)行,事務(wù)只能一個(gè)接著一個(gè)地執(zhí)行,但不能并發(fā)執(zhí)行。如果僅僅通過“行級(jí)鎖”是無法實(shí)現(xiàn)事務(wù)序列化的,必須通過其他機(jī)制保證新插入的數(shù)據(jù)不會(huì)被剛執(zhí)行查詢操作的事務(wù)訪問到。
隔離級(jí)別越高,越能保證數(shù)據(jù)的完整性和一致性,但是對(duì)并發(fā)性能的影響也越大。對(duì)于多數(shù)應(yīng)用程序,可以優(yōu)先考慮把數(shù)據(jù)庫系統(tǒng)的隔離級(jí)別設(shè)為Read Committed。它能夠避免臟讀取,而且具有較好的并發(fā)性能。盡管它會(huì)導(dǎo)致不可重復(fù)讀、虛讀和第二類丟失更新這些并發(fā)問題,在可能出現(xiàn)這類問題的個(gè)別場(chǎng)合,可以由應(yīng)用程序采用悲觀鎖或樂觀鎖來控制。
posted on 2014-08-12 09:36 順其自然EVO 閱讀(226) 評(píng)論(0) 編輯 收藏 所屬分類: 數(shù)據(jù)庫