數據庫事務隔離級別 - 分析臟讀 & 不可重復讀 & 幻讀


一 數據庫事務的隔離級別

數據庫事務的隔離級別有4個,由低到高依次為Read uncommitted 、Read committed 、Repeatable read 、Serializable ,這四個級別可以逐個解決臟讀 、不可重復讀 、幻讀這幾類問題。

 

1. Read UnCommitted(讀未提交)

最低的隔離級別。一個事務可以讀取另一個事務並未提交的更新結果。

2. Read Committed(讀提交)

大部分數據庫采用的默認隔離級別。一個事務的更新操作結果只有在該事務提交之后,另一個事務才可以的讀取到同一筆數據更新后的結果。

3. Repeatable Read(重復讀)

mysql的默認級別。整個事務過程中,對同一筆數據的讀取結果是相同的,不管其他事務是否在對共享數據進行更新,也不管更新提交與否。

4. Serializable(序列化)

最高隔離級別。所有事務操作依次順序執行。注意這會導致並發度下降,性能最差。通常會用其他並發級別加上相應的並發鎖機制來取代它。

 

 

 

二 不同事務級別帶來的並發問題

1 臟讀

臟讀發生在一個事務A讀取了被另一個事務B修改,但是還未提交的數據。假如B回退,則事務A讀取的是無效的數據。這跟不可重復讀類似,但是第二個事務不需要執行提交。 

 

2 不可重復讀

在基於鎖的並行控制方法中,如果在執行select時不添加讀鎖,就會發生不可重復讀問題。

在多版本並行控制機制中,當一個遇到提交沖突的事務需要回退但卻被釋放時,會發生不可重復讀問題。

在上面這個例子中,事務2提交成功,它所做的修改已經可見。然而,事務1已經讀取了一個其它的值。在序列化和可重復讀的隔離級別中,數據庫管理系統會返回舊值,即在被事務2修改之前的值。在提交讀和未提交讀隔離級別下,可能會返回被更新的值,這就是“不可重復讀”。

 

有兩個策略可以防止這個問題的發生:

(1) 推遲事務2的執行,直至事務1提交或者回退。這種策略在使用鎖時應用。

(2) 而在多版本並行控制中,事務2可以被先提交。而事務1,繼續執行在舊版本的數據上。當事務1終於嘗試提交時,數據庫會檢驗它的結果是否和事務1、事務2順序執行時一樣。如果是,則事務1提交成功。如果不是,事務1會被回退。

 

 

幻讀 

幻讀發生在當兩個完全相同的查詢執行時,第二次查詢所返回的結果集跟第一個查詢不相同。

發生的情況:沒有范圍鎖。

 

 

三 例子比較不可重復讀和幻讀

1 不可重復讀

不可重復讀的重點是修改: 同樣的條件, 你讀取過的數據, 再次讀取出來發現值不一樣了

例子:

在事務1中,Mary 讀取了自己的工資為1000,操作並沒有完成 

con1 = getConnection();  
select salary from employee empId ="Mary";  

在事務2中,這時財務人員修改了Mary的工資為2000,並提交了事務. 

con2 = getConnection();  
update employee set salary = 2000;  
con2.commit(); 

在事務1中,Mary 再次讀取自己的工資時,工資變為了2000 

select salary from employee empId ="Mary"; 

在一個事務中前后兩次讀取的結果並不致,導致了不可重復讀。

 

 

 2 幻讀

幻讀的重點在於 新增或者刪除 (數據條數變化)。同樣的條件, 第1次和第2次讀出來的記錄數不一樣

例子:

目前工資為1000的員工有10人。 
事務1,讀取所有工資為1000的員工。 

con1 = getConnection();  
Select * from employee where salary =1000;  

共讀取10條記錄 

這時另一個事務向employee表插入了一條員工記錄,工資也為1000 

con2 = getConnection();  
Insert into employee(empId,salary) values("Lili",1000);  
con2.commit();  

事務1再次讀取所有工資為1000的員工 

select * from employee where salary =1000;  

共讀取到了11條記錄,這就像產生了幻讀。 


免責聲明!

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



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