資料庫鎖和資料庫隔離級別

2021-09-20 23:29:43 字數 3205 閱讀 9081

最近突然發現忘了資料庫鎖和資料庫隔離級別,時常弄混它們之間的關係。為此特此寫下此部落格,以方便自己複習,同時也可以幫助博友。

資料庫鎖

資料庫鎖就是事務t在對某個資料物件(例如表、記錄等)操作之前,先向系統發出請求,對其加鎖。加鎖後事務t就對該資料物件有了一定的控制,在事務t釋放它的鎖之前,其它的事務不能更新此資料物件。

資料庫鎖是實現併發控制的重要技術,但是「鎖」會帶來系統額外的開銷。所以需要注意選擇封鎖粒度時必須同時考慮開銷和併發度兩個因素,進行權衡,以求得最優的效果。

鎖的型別主要有兩種型別排它鎖(也叫獨佔鎖)和共享鎖,當然還有很多教程增加了一種--更新鎖

共享(s)鎖:多個事務可封鎖乙個共享頁;任何事務都不能修改該頁; 通常是該頁被讀取完畢,s鎖立即被釋放。在執行select語句的時候需要給操作物件(表或者一些記錄)加上共享鎖,但加鎖之前需要檢查是否有排他鎖,如果沒有,則可以加共享鎖(乙個物件上可以加n個共享鎖),否則不行。共享鎖通常在執行完select語句之後被釋放,當然也有可能是在事務結束(包括正常結束和異常結束)的時候被釋放,主要取決與資料庫所設定的事務隔離級別。 

排它(x)鎖:僅允許乙個事務封鎖此頁;其他任何事務必須等到x鎖被釋放才能對該頁進行訪問;x鎖一直到事務結束才能被釋放。執行insert、update、delete語句的時候需要給操作的物件加排他鎖(我感覺在執行insert的時候應該是在表級加排他鎖),在加排他鎖之前必須確認該物件上沒有其他任何鎖,一旦加上排他鎖之後,就不能再給這個物件加其他任何鎖。排他鎖的釋放通常是在事務結束的時候(當然也有例外,就是在資料庫事務隔離級別被設定成read uncommitted(讀未提交資料)的時候,這種情況下排他鎖會在執行完更新操作之後就釋放,而不是在事務結束的時候)。 

更新(u)鎖:用來預定要對此頁施加x鎖,它允許其他事務讀,但不允許再施加u鎖或x鎖;當被讀取的頁將要被更新時,則公升級為x鎖;u鎖一直到事務結束時才能被釋放。資料庫是支援在乙個事務中進行自動鎖公升級的,例如,在某個事務中先執行select語句,後執行update語句,這兩條語句操作了同乙個物件,並且假定共享鎖是在事務結束的時候被釋放的。如果資料庫不支援自動鎖公升級,那麼當update語句請求排他鎖的時候將不能成功。因為之前select語句的共享鎖沒有被釋放,那麼事務就進入了無限等待,即死鎖。有了自動鎖公升級,在執行update語句的時候就可以將之前加的共享鎖公升級為排他鎖,但有個前提,就是這個共享鎖必須是本事務自己加的,而且在操作物件上沒有在加其他任何鎖,否則共享鎖是不能被公升級為排他鎖的,必須等待其他鎖的釋放。

因為通常在執行更新操作的時候要先查詢,也就是我們通常會在update語句和delete語句中加where子句。那麼,有的資料庫系統可能會在執行查詢的時候先給操作物件加共享鎖,然後在更新的時候加排他鎖,但這麼做會有問題,也就是如果兩個事務同時要更新乙個物件,都先給這個物件加了共享鎖,當要更新的時候,都請求公升級鎖,但由於這個物件上存在對方事務加的共享鎖。。所以無法公升級。這樣兩個事務就在等待對方釋放共享鎖,進入死鎖狀態。更新鎖就是為了解決這個問題,即在執行查詢操作的時候加的不是共享鎖而是更新鎖(乙個物件上只能有乙個更新鎖和n個共享鎖),當要更新的時候,再將更新鎖公升級為排他鎖,公升級前提是這個物件上只有本事務加的更新鎖,沒有其他任何鎖了。其實,,我想,如果在執行查詢的時候就給事務加排他鎖不也能解決死鎖問題嗎,但這樣似乎會減弱系統的併發效能。

資料庫的事務隔離級別

在資料庫操作中,為了有效保證併發讀取資料的正確性,提出的事務隔離級別。

在沒有資料庫的事務隔離級別時會出現如下問題:

更新丟失

兩個事務都同時更新一行資料,但是第二個事務卻中途失敗退出,導致對資料的兩個修改都失效了。這是因為系統沒有執行任何的鎖操作,因此併發事務並沒有被隔離開來。

髒讀

乙個事務開始讀取了某行資料,但是另外乙個事務已經更新了此資料但沒有能夠及時提交。這是相當危險的,因為很可能所有的操作都被回滾。

不可重複讀

不可重複讀(non-repeatable reads):乙個事務對同一行資料重複讀取兩次,但是卻得到了不同的結果。

包括以下情況:

(1) 事務t1讀取某一資料後,事務t2對其做了修改,當事務t1再次讀該資料時得到與前一次不同的值。

(2) 幻讀(phantom reads):事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的資料或者缺少了第一次查詢**現的資料(這裡並不要求兩次查詢的sql語句相同)。這是因為在兩次查詢過程中有另外乙個事務插入資料造成的。

為了避免上面出現的幾種情況,在標準sql規範中,定義了4個事務隔離級別,不同的隔離級別對事務的處理不同。

未授權讀取

也稱為讀未提交(read uncommitted):允許髒讀取,但不允許更新丟失。如果乙個事務已經開始寫資料,則另外乙個事務則不允許同時進行寫操作,但允許其他事務讀此行資料。該隔離級別可以通過「排他寫鎖」實現。

授權讀取

也稱為讀提交(read committed):允許不可重複讀取,但不允許髒讀取。這可以通過「瞬間共享讀鎖」和「排他寫鎖」實現。讀取資料的事務允許其他事務繼續訪問該行資料,但是未提交的寫事務將會禁止其他事務訪問該行。

可重複讀取(repeatable read)

可重複讀取(repeatable read):禁止不可重複讀取和髒讀取,但是有時可能出現幻影資料。這可以通過「共享讀鎖」和「排他寫鎖」實現。讀取資料的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。

序列化(serializable)

序列化(serializable):提供嚴格的事務隔離。它要求事務序列化執行,事務只能乙個接著乙個地執行,但不能併發執行。如果僅僅通過「行級鎖」是無法實現事務序列化的,必須通過其他機制保證新插入的資料不會被剛執行查詢操作的事務訪問到。

隔離級別越高,越能保證資料的完整性和一致性,但是對併發效能的影響也越大。對於多數應用程式,可以優先考慮把資料庫系統的隔離級別設為read committed。它能夠避免髒讀取,而且具有較好的併發效能。儘管它會導致不可重複讀、虛讀和第二類丟失更新這些併發問題,在可能出現這類問題的個別場合,可以由應用程式採用悲觀鎖或樂觀鎖來控制。

資料庫鎖和資料庫隔離級別

最近突然發現忘了資料庫鎖和資料庫隔離級別,時常弄混它們之間的關係。為此特此寫下此部落格,以方便自己複習,同時也可以幫助博友。資料庫鎖 資料庫鎖就是事務t在對某個資料物件 例如表 記錄等 操作之前,先向系統發出請求,對其加鎖。加鎖後事務t就對該資料物件有了一定的控制,在事務t釋放它的鎖之前,其它的事務...

資料庫事務 和 資料庫隔離級別

有一天同事問我,晨哥晨哥,什麼是資料庫的隔離級別,我,額,稍等,冒汗,以前看過,現在忘了。有時間寫一篇,下次再忘了還能看看。主要是自己看,順便滿足一下自己寫作的慾望,如果你不小心看到了,證明咱倆有緣分,別因為我寫的不好噴我。你以為第一件事是介紹資料庫隔離級別的定義嗎,錯,我們要先了解為什麼有資料庫的...

資料庫鎖 隔離級別

併發控制主要是為了多執行緒操作時帶來的資源讀寫問題。如果不加以空間可能會出現死鎖,讀髒資料 不可重複讀 丟失更新等異常。併發操作可以通過加鎖的方式進行控制,鎖又可分為樂觀鎖和悲觀鎖。悲觀鎖 pessimistic locking 併發模式假定系統中存在足夠多的資料修改操作,以致於任何確定的讀操作都可...