在資料庫系統中,隔離是定義乙個操作對資料所做的改變如何/何時對其它的並行操作可見。
隔離並不改變鎖本身的行為,而是通過實行不同的鎖機制實現的。比如是否加鎖,加多長時間的鎖,加什麼型別的鎖等。同時,也會影響排它情況下的可見性(如read uncommited)。
資料庫系統有四個隔離級別。對資料庫使用何種隔離級別要審慎分析,因為
1. 維護乙個最高的隔離級別雖然會防止資料的出錯,但是卻導致了並行度的損失,以及導致死鎖出現的可能性增加。
2. 然而,降低隔離級別,卻會引起一些難以發現的bug。
一、read uncommitted(未提交讀):
不新增共享鎖。所以其它事務b可以在事務a對記錄的讀取過程中修改同一記錄,可能會導致a讀取的資料是乙個被破壞的或者說不完整不正確的資料。
另外,在事務a中可以讀取到事務b(未提交)中修改的資料。比如事務b對r記錄修改了,但未提交。此時,在事務a中讀取r記錄,讀出的是被b修改過的資料。
可能發生的問題:髒讀。
二、read committed(提交讀):
在事務a中讀取資料時對記錄新增共享鎖,但讀取結束立即釋放。其它事務b對這個記錄的試圖修改會一直等待直到a中的讀取過程結束,而不需要整個事務a的結束。所以,在事務a的不同階段對同一記錄的讀取結果可能是不同的。
可能發生的問題:不可重複讀。
三、repeatable read(可重複讀):
對於讀出的記錄,新增共享鎖直到事務a結束。其它事務b對這個記錄的試圖修改會一直等待直到事務a結束。
可能發生的問題:當執行乙個範圍查詢時,可能會發生幻讀。
四、serializable(序列化):
新增範圍鎖(比如表鎖,頁鎖等,關於range lock,我也沒有很深入的研究),直到事務a結束。以此阻止其它事務b對此範圍內的insert,update等操作。
幻讀,髒讀,不可重複讀等問題都不會發生。
我們看到,當執行不同的隔離級別時,可能會發生各種各樣不同的問題。下面對它們進行總結並舉例說明。
1、髒讀
髒讀發生在乙個事務a讀取了被另乙個事務b修改,但是還未提交的資料。假如b回退,則事務a讀取的是無效的資料。這跟不可重複讀類似,但是第二個事務不需要執行提交。
2、不可重複讀
在基於鎖的並行控制方法中,如果在執行select時不新增讀鎖,就會發生不可重複讀問題。
在多版本並行控制機制中,當乙個遇到提交衝突的事務需要回退但卻被釋放時,會發生不可重複讀問題。
例如有兩個事務,事務2提交成功,它所做的修改已經可見。然而,事務1已經讀取了乙個其它的值。在序列化和可重複讀的隔離級別中,資料庫管理系統會返回舊值,即在被事務2修改之前的值。在提交讀和未提交讀隔離級別下,可能會返回被更新的值,這就是「不可重複讀」。
有兩個策略可以防止這個問題的發生:
1. 推遲事務2的執行,直至事務1提交或者回退。這種策略在使用鎖時應用。
2. 而在多版本並行控制中,事務2可以被先提交。而事務1,繼續執行在舊版本的資料上。當事務1終於嘗試提交時,資料庫會檢驗它的結果是否和事務1、事務2順序執行時一樣。如果是,則事務1提交成功。如果不是,事務1會被回退。
發生的情況:沒有範圍鎖。
如何避免:實行序列化隔離模式,在任何乙個低階別的隔離中都可能會發生。
3、幻讀
幻讀發生在當兩個完全相同的查詢執行時,第二次查詢所返回的結果集跟第乙個查詢不相同。
總結如下所示:
隔離級別
是否存在髒讀
是否存在不可重複讀
是否存在幻讀
read uncommited(未提交讀) yy
yread commited (提交讀 oraclel預設)ny
yrepeatable read(可重複讀(mysql預設))nn
yserializable(可
序列化)
資料庫隔離級別
read uncommited 讀未提交 最低級別,可讀取未提交事物的資料,這會導致髒讀,比如 某時刻會話a修改了乙個資料,但還未提交,此時會話b,讀取了該資料,這是,會話a回滾了事物,這就導致資料出現了不一致狀態,這就是髒讀 read commited 提交讀 避免了髒讀,但會導致不可重複讀,例如...
資料庫隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable,這四個級別可以逐個解決髒讀 不可重複讀 幻讀這幾類問題。可能出現 不會出現 髒讀 不可重複讀 幻讀read uncommitted re...
資料庫隔離級別
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable,這四個級別可以逐個解決髒讀 不可重複讀 幻讀這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted rea...