臟讀(臟數據、臟頁)、不可重復讀、幻讀


一、臟讀(讀到未提交的數據)

在理解臟讀之前,需要理解臟數據的概念。

臟數據是指事務對緩沖池中行記錄的修改,並且還沒有提交。

注意臟數據和臟頁是完全不同的兩種概念,臟頁指的是在緩沖池中已經被修改的頁,但是還沒有刷新到磁盤中,即數據庫實例內存中的頁和磁盤中的頁的數據不一致。臟頁的讀取是非常正常的,臟頁是數據庫實例內存和磁盤異步造成的,這並不影響數據的一致性,臟頁最終會被刷新到磁盤中。

臟讀指的是在不同事務下,當前事務可以讀取到另外事務未提交的數據,簡單來說就是可以讀到臟數據。

和臟頁不同,如果讀到了臟數據,即一個事務讀取到了另外一個事務未提交的事務,顯然違反了了事務的隔離性

下面舉個例子

轉賬事務 取款事務
1 開始事務
2 開始事務
3 查新賬戶余額為2000
4 取款1000元,余額改為1000
5 查詢賬戶余額為1000(臟讀)
6 取款發生錯誤,事務回滾,余額變為2000
7 轉入2000,余額變為3000(1000+2000)
8 提交事務
備注 正常邏輯此時賬戶為4000元

臟讀現象在實際生產環境並不常見,因為臟讀發生的條件是需要事務的隔離級別為READ UNCOMMITTED,而目前絕大多數數據庫都至少設置成READ COMMITTED。InnoDB存儲引擎默認事務隔離級別為READ REPEATABLE。

二、不可重復讀(前后讀取到的數據內容不一致)

不可重復讀指在一個事務內多次讀取同一數據,在這個事務還沒結束時,另一個事務也訪問該數據,並修改了改數據,因此在第一個事務中的兩次讀取數據之間,由於第二個事務的修改,第一個事務兩次讀取到的數據可能是不一樣的。這樣就發生了在一個事務內兩次讀取的數據是不一樣的,這種情況稱為不可重復讀。

注意和臟讀的區別:臟讀讀取到的是未提交的數據,不可重復讀讀到的是已提交的數據,但違反了數據庫事務的一致性

舉個例子:

事務A 事務B
1 開始事務
2 第一次查詢,小明為20歲
3 開始事務
4 其他操作
5 更改小明年齡為25
6 提交事務
7 第二次查詢,小明年齡為25
備注 兩次讀取到數據不一致

在InnoDB存儲引擎中,默認事務隔離級別為READ REPEATABLE,通過使用Next-Key Lock算法來避免不可重復讀的問題。

三、幻讀(前后讀取數據總量不一致)

事務A在執行讀取操作,需要兩次統計數據的總量,前一次查詢數據總量后,此時事務B執行了新增數據的操作並提交后,這個時候事務A讀取的數據總量和之前統計的不一樣,就像產生了幻覺一樣,平白無故的多了幾條數據,成為幻讀。

舉個例子:

事務A 事務B
1 開始事務
2 第一次查詢,數據總量為100條
3 開始事務
4 其他操作
5 增加100條數據
6 提交事務
7 第二次查詢,數據總量為200條
備注 兩次讀取到數據總量不一致

不可重復讀和幻讀到底有什么區別呢?
(1)不可重復讀是讀取了其他事務更改的數據,針對insert與update操作

解決:使用行級鎖,鎖定該行,事務A多次讀取操作完成后才釋放該鎖,這個時候才允許其他事務更改剛才的數據。

(2)幻讀是讀取了其他事務新增的數據,針對insert與delete操作

解決:使用表級鎖,鎖定整張表,事務A多次讀取數據總量之后才釋放該鎖,這個時候才允許其他事務新增數據。


免責聲明!

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



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