數據庫的讀現象淺析

「讀現象」是多個事務併發執行時,在讀取數據方面可能碰到的情況。先了解它們有助於理解各隔離級別的含義。其中包括髒讀、不可重複讀和幻讀。數據庫

髒讀

髒讀又稱無效數據的讀出,是指在數據庫訪問中,事務T1將某一值修改,而後事務T2讀取該值,此後T1由於某種緣由撤銷對該值的修改,這就致使了T2所讀取到的數據是無效的。併發

髒讀就是指當一個事務正在訪問數據,而且對數據進行了修改,而這種修改尚未提交(commit)到數據庫中,這時,另一個事務也訪問這個數據,而後使用了這個數據。由於這個數據是尚未提交的數據,那麼另一個事務讀到的這個數據是髒數據,依據髒數據所作的操做多是不正確的。spa

舉例說明:code

在下面的例子中,事務2修改了一行,可是沒有提交,事務1讀了這個沒有提交的數據。如今若是事務2回滾了剛纔的修改或者作了另外的修改的話,事務1中查到的數據就是不正確的了。事務

事務一 事務二
/* 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的數據了。因此,事務一讀到了一條髒數據。ip

不可重複讀

不可重複讀,是指在數據庫訪問中,一個事務範圍內兩個相同的查詢卻返回了不一樣數據。這是因爲查詢時系統中其餘事務修改的提交而引發的。好比事務T1讀取某一數據,事務T2讀取並修改了該數據,T1爲了對讀取值進行檢驗而再次讀取該數據,便獲得了不一樣的結果。get

一種更易理解的說法是:在一個事務內,屢次讀同一個數據。在這個事務尚未結束時,另外一個事務也訪問該同一數據。那麼,在第一個事務的兩次讀數據之間。因爲第二個事務的修改,那麼第一個事務讀到的數據可能不同,這樣就發生了在一個事務內兩次讀到的數據是不同的,所以稱爲不可重複讀,即原始讀取不可重複。it

舉例說明:io

在基於鎖的併發控制中「不可重複讀(non-repeatable read)」現象發生在當執行SELECT 操做時沒有得到讀鎖(read locks)或者SELECT操做執行完後立刻釋放了讀鎖; 多版本併發控制中當沒有要求一個提交衝突的事務回滾也會發生「不可重複讀(non-repeatable read)」現象。table

事務一 事務二
/* Query 1 */

SELECT * FROM users WHERE id = 1;
 
 
/* Query 2 */ 
UPDATE users SET age = 21 WHERE id = 1;

COMMIT;

/* in multiversion concurrency
control, or lock-based READ COMMITTED */

/* Query 1 */
SELECT * FROM users WHERE id = 1;

COMMIT; 
/*lock-based REPEATABLE READ */
 

在這個例子中,事務2提交成功,所以他對id爲1的行的修改就對其餘事務可見了。可是事務1在此前已經從這行讀到了另一個「age」的值。

幻讀

幻讀是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,好比這種修改涉及到表中的「所有數據行」。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入「一行新數據」。那麼,之後就會發生操做第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺同樣.通常解決幻讀的方法是增長範圍鎖RangeS,鎖定檢鎖範圍爲只讀,這樣就避免了幻讀。  

幻讀(phantom read)」是不可重複讀(Non-repeatable reads)的一種特殊場景:當事務沒有獲取範圍鎖的狀況下執行SELECT … WHERE操做可能會發生「幻影讀(phantom read)」。

舉例說明:

當事務1兩次執行SELECT … WHERE檢索必定範圍內數據的操做中間,事務2在這個表中建立了(如INSERT)了一行新數據,這條新數據正好知足事務1的「WHERE」子句。

事務一 事務二
/* Query 1 */

SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
 
 
/* Query 2 */ 
INSERT INTO users VALUES ( 3, 'Bob', 27 );

COMMIT;

/* Query 1 */
SELECT * FROM users
WHERE age BETWEEN 10 AND 30;
 

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

解決方案

要想解決髒讀、不可重複讀、幻讀等讀現象,那麼就須要提升事務的隔離級別。但與此同時,事務的隔離級別越高,併發能力也就越低。因此,還須要讀者根據業務須要進行權衡。

參考資料

維基百科

相關文章
相關標籤/搜索