數據庫讀現象之臟讀、不可重復讀、幻讀


一 數據庫讀現象

數據庫管理軟件的“讀現象”指的是當多個事務並發執行時,在讀取數據方面可能碰到的問題,包括有臟讀、不可重復讀和幻讀。

ps:對於一些數據庫管理軟件會自帶相應的機制去解決臟讀、不可重復讀、幻讀等問題,因為這些自帶的機制,下述的一些實驗現象可能在某一數據庫管理軟件的默認機制下並不成立,即我們並不能在所有數據庫管理軟件中看到所有的讀現象。所以此處我們暫且拋開具體的某個數據庫管理軟件的默認機制的干擾,暫時假設沒有附加任何機制為前提,單純地去理解數據庫的讀現象。

1.1、臟讀 (dirty read)

臟讀就是當在某一個事務之中,出現修改之后的查詢,得到的數據是未提交的數據庫數據。

事務T2更新了一行記錄的內容,但是並沒有提交所做的修改。

事務T1讀取更新后的行,然后T1執行回滾操作,取消了剛才所做的修改。此時T1所讀取的行就無效了,稱之為臟數據。

舉例

事務一 事務二
/* Query 1 */ SELECT age FROM users WHERE id = 1; /* will read 20 */
/* Query 2 */ UPDATE users SET age = 21 WHERE id = 1; /* No commit here */
/* Query 1 */ SELECT age FROM users WHERE id = 1; /* will read 21 */
ROLLBACK; /* lock-based DIRTY READ */

在這個例子中,事務2回滾后就沒有id是1,age是21的數據了。所以,事務一讀到了一條臟數據。

1.2、不可重復讀取 (nonrepeatable read)

當我們讀取的數據在其他事務之中被修改了,這個時候本事務中沒有及時讀取正確內容,即稱之為不可重復讀現象。

事務T1讀取一行記錄,緊接着事務T2修改了T1剛才讀取的那一行記錄並且提交了。

然后T1又再次讀取這行記錄,發現與剛才讀取的結果不同。這就稱為“不可重復”讀,因為T1原來讀取的那行記錄已經發生了變化。

舉例

在基於鎖的並發控制中“不可重復讀(non-repeatable read)”現象發生在當執行SELECT 操作時沒有獲得讀鎖(read locks)或者SELECT操作執行完后馬上釋放了讀鎖; 多版本並發控制中當沒有要求一個提交沖突的事務回滾也會發生“不可重復讀(non-repeatable read)”現象。

事務一 事務二
/* Query 1 */ SELECT * FROM users WHERE id = 1;
/* Query 2 */ UPDATE users SET age = 21 WHERE id = 1; COMMIT; /* in multiversion concurrencycontrol, or lock-based READ COMMITTED */
/* Query 1 */ SELECT * FROM users WHERE id = 1; COMMIT; /*lock-based REPEATABLE READ */

在這個例子中,事務2提交成功,因此他對id為1的行的修改就對其他事務可見了。但是事務1在此前已經從這行讀到了另外一個“age”的值。

1.3、幻像讀取 (phantom read)

當在一個事務中讀取某一個范圍之內的數據時,另一個事務修改了在本事務查詢范圍之內的數據,此時該事務讀取不到新修改的數據,這種現象稱之為幻讀。

幻讀(phantom read)”是不可重復讀(Non-repeatable reads)的一種特殊場景:
當事務沒有獲取范圍鎖的情況下執行SELECT … WHERE操作有可能會發生“幻影讀(phantom read)”。

事務T1讀取或修改了指定的WHERE子句所返回的結果集。

然后事務T2新插入一行記錄,這行記錄恰好可以滿足T1所使用的查詢條件中的WHERE 子句的條件。

然后T1又使用相同的查詢再次對表進行檢索,但是此時卻看到了事務T2剛才插入的新行或者發現了處於WHRE子句范圍內,但卻未曾修改過的記錄。就好像“幻覺”一樣,因為對T1來說這一行就像突然出現的一樣。

一般解決幻讀的方法是增加范圍鎖RangeS,鎖定檢鎖范圍為只讀,這樣就避免了幻讀。

舉例

當事務1兩次執行SELECT … WHERE檢索一定范圍內數據的操作中間,事務2在這個表中創建了(如INSERT)了一行新數據,這條新數據正好滿足事務1的“WHERE”子句。

事務一 事務二
/* Query 1 */ SELECT * FROM usersWHERE age BETWEEN 10 AND 30;
/* Query 2 */ INSERT INTO users VALUES ( 3, 'Bob', 27 ); COMMIT;
/* Query 1 */ SELECT * FROM usersWHERE age BETWEEN 10 AND 30;

在這個例子中,事務一執行了兩次相同的查詢操作。但是兩次操作中間事務二向數據庫中增加了一條符合事務一的查詢條件的數據,導致幻讀。

二 解決方案

其實,臟寫、臟讀、不可重復讀、幻讀,都是因為業務系統會多線程並發執行,每個線程可能都會開啟一個事務,每個事務都會執行增刪改查操作。然后數據庫會並發執行多個事務,多個事務可能會並發地對緩存頁里的同一批數據進行增刪改查操作,於是這個並發增刪改查同一批數據的問題,可能就會導致我們說的臟寫、臟讀、不可重復讀、幻讀這些問題。

所以這些問題的本質,都是數據庫的多事務並發問題,那么為了解決多事務並發帶來的臟讀、不可重復讀、幻讀等讀等問題,數據庫才設計了鎖機制事務隔離機制、MVCC 多版本隔離機制,用一整套機制來解決多事務並發問題,下面我們來分別介紹一下它們


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM