數據庫讀髒、不可重複讀、幻讀

當多個事務併發執行時,在讀取數據庫數據時會遇到:數據庫讀髒、不可重複讀、幻讀。瞭解它們有助於理解各隔離級別的含義。

 

一、事務的隔離級別

事務:是指作爲單個邏輯工作單元執行的一系列操作,要麼全做,要麼不做。 

事務的ACID特性:原子性、一致性、持久性、隔離性。

在數據庫事務的ACID四個屬性中,隔離性是一個最常放鬆的一個。可以在數據操作過程中利用數據庫的鎖機制或者多版本併發控制機制獲取更高的隔離等級。但是,隨着數據庫隔離級別的提高,數據的併發能力也會有所下降。所以,如何在併發性和隔離性之間做一個很好的權衡就成了一個至關重要的問題。不同的隔離級別會導致和解決不同的讀現象。

二、讀髒

讀髒,即讀到了髒數據,無效的數據。

當一個事務正在訪問數據,並且對數據進行了修改,而這種修改還沒有提交(commit)到數據庫中,這時,另外一個事務也訪問這個數據,然後使用了這個數據。因爲這個數據是還沒有提交的數據,那麼另外一個事務讀到的這個數據是髒數據,依據髒數據所做的操作可能是不正確的。

舉個例子,當我在本地修改某個對數據庫操作類的代碼後,還沒有提交,這時,其他人用了我的代碼,這就是讀髒數據。因爲我沒有提交代碼,隨時可能修改代碼,而其他人用剛纔的代碼獲取的就是髒數據了。

這種情況下,多個開發者併發性很高,其他人隨時可以讀取我的代碼,但是極容易讀髒數據,所以我們代碼的隔離性很差。

我們並不希望代碼在未提交的情況下,被其他人讀取,因此我們需要提高代碼的隔離性。 

三、不可重複讀

爲了解決讀髒數據的問題,我們通過提高代碼的隔離性來實現。在我修改代碼時,不允許其他人讀取訪問我的代碼,只有在提交代碼後才能訪問,這樣子就不會讀髒數據。

這樣子提高了代碼之間的隔離性,併發性就降低了,因爲需要等我把代碼提交後其他人才能讀取。但是會存在不可重複讀問題。

再舉個例子:張三和我同時訪問某個類的代碼,其中的一個常量被我改動並提交了,當張三再次訪問這段代碼時,得到的內容不一樣,這就是不可重複讀。

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

要解決不可重複讀的問題,就需要在張三讀取代碼的時候,我不能對其進行訪問,這樣子就解決了不可重複讀的問題,代碼的隔離性又提高了,併發性降低了。

四、幻讀

當張三在讀某個類的代碼時,我對這個類不進行修改,解決了不可重複讀的問題,但是我增加了一些類,在提升了隔離性之後,雖然我不會修改張三正在讀的類,張三也不會讀我正在修改的類。但是我可能會增加或者刪除幾個類。這時候和張三之前讀取到的類的總個數就有了變化。也就是說,張三之前讀到的數據就不準確了。這就是幻讀。

幻讀。指同一個事務內多次查詢返回的結果集不一樣(比如增加了或者減少了行記錄)。比如同一個事務A內第一次查詢時候有n條記錄,但是第二次同等條件下查詢卻又n+1條記錄,這就好像產生了幻覺。

解決幻讀就是當張三在讀代碼的時候,我不對代碼進行任何操作,我們之間的隔離性最高,併發性最低。

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

 

事務的隔離性上,從低到高可能產生的讀現象分別是:髒讀、不可重複讀、幻讀。

髒讀指讀到了未提交的數據。

不可重複讀指一次事務內的多次相同查詢,讀取到了不同的結果。

幻讀師不可重複讀的特殊場景。一次事務內的多次範圍查詢得到了不同的結果。

通過在寫的時候加鎖,可以解決髒讀。

通過在讀的時候加鎖,可以解決不可重複讀。

通過串行化,可以解決幻讀。

以上這幾種解決方案其實是數據庫的幾種隔離級別。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章