qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          數(shù)據(jù)庫鎖和數(shù)據(jù)庫隔離級別

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

          posted on 2014-08-12 09:36 順其自然EVO 閱讀(224) 評論(0)  編輯  收藏 所屬分類: 數(shù)據(jù)庫

          <2014年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 泽州县| 且末县| 石泉县| 阳城县| 阿拉尔市| 枝江市| 崇明县| 涟源市| 游戏| 临高县| 长顺县| 清苑县| 西华县| 平舆县| 玉环县| 陇西县| 阜康市| 都兰县| 平罗县| 蒲城县| 百色市| 宿松县| 红安县| 乌海市| 台安县| 横山县| 渝北区| 淅川县| 家居| 枣庄市| 伽师县| 新密市| 北宁市| 漯河市| 梁河县| 盐城市| 郓城县| 甘洛县| 边坝县| 精河县| 河西区|