臟讀、不可重復讀和幻讀的區別


事務4個隔離界別

Read Uncommitted, Read commited, Repeatable read, Serializable
Read Uncommitted.  最低的隔離級別,Read Uncommitted最直接的效果就是一個事務可以讀取另一個事務並未提交的更新結果。
 
Read Committed.  Read Committed通常是大部分數據庫采用的默認隔離級別,它在Read Uncommitted隔離級別基礎上所做的限定更進一步, 在該隔離級別下,一個事務的更新操作結果只有在 該事務提交之后,另一個事務才可能讀取到同一筆數據更新后的結果。 所以,Read Committed可以避免Read Uncommitted隔離級別下存在的臟讀問題, 但,無法避免不可重復讀取和幻讀的問題。

Repeatable Read.  Repeatable Read隔離級別可以 保證在整個事務的過程中對同一筆數據的讀取結果是相同的,不管其他事務是否同時在對同一筆數據進行更新,也不管其他事務對同一筆數據的更新提交與否。 Repeatable Read隔離級別避免了臟讀和不可重復讀取的問題,但無法避免幻讀。( mysql默認隔離級別

Serializable.  最為嚴格的隔離級別,所有的事務操作都必須依次順序執行,可以避免其他隔離級別遇到的所有問題,是最為安全的隔離級別, 但同時也是性能最差的隔離級別,因為所有的事務在該隔離級別下都需要依次順序執行,所以,並發度下降,吞吐量上不去,性能自然就下來了。 因為該隔離級別極大的影響系統性能,所以,很少場景會使用它。通常情況下,我們會使用其他隔離級別加上相應的並發鎖的機制來控制對數據的訪問,這樣既保證了系統性能不會損失太大,也能夠一定程度上保證數據的一致性。
 

並發問題

臟讀

 ( 針對未提交數據)如果一個事務中對數據進行了更新,但 事務還沒有提交,另一個事務可以“看到”該事務沒有提交的更新結果,這樣造成的問題就是,如果第一個事務回滾,那么,第二個事務在此之前所“看到”的數據就是一筆臟數據。

不可重復讀

針對其他提交前后,讀取數據本身的對比)不可重復讀取是指同一個事務在整個事務過程中對同一筆數據進行讀取,每次讀取結果都不同。如果事務1在事務2的更新操作之前讀取一次數據,在事務2的更新操作之后再讀取同一筆數據一次,兩次結果是不同的,所以,Read Uncommitted也無法避免不可重復讀取的問題。

幻讀

針對其他提交前后,讀取數據條數的對比) 幻讀是指同樣一筆查詢在整個事務過程中多次執行后,查詢所得的結果集是不一樣的。幻讀針對的是多筆記錄。在Read Uncommitted隔離級別下, 不管事務2的插入操作是否提交,事務1在插入操作之前和之后執行相同的查詢,取得的結果集是不同的,所以,Read Uncommitted同樣無法避免幻讀的問題。
 

不可重復讀和幻讀區別

對於不可重復讀和幻讀,可以借用下面的例子理解:

 

不可重復讀

 

不可重復讀的重點是修改:

同樣的條件, 你讀取過的數據, 再次讀取出來發現值不一樣了

例子:

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

Java代碼   收藏代碼
  1. con1 = getConnection();  
  2. select salary from employee empId ="Mary";  
在事務2中,這時財務人員修改了Mary的工資為2000,並提交了事務. 
Java代碼   收藏代碼
  1. con2 = getConnection();  
  2. update employee set salary = 2000;  
  3. con2.commit();  
在事務1中,Mary 再次讀取自己的工資時,工資變為了2000 
Java代碼   收藏代碼
  1. //con1  
  2. select salary from employee empId ="Mary";  
在一個事務中前后兩次讀取的結果並不致,導致了不可重復讀。

幻讀

幻讀的重點在於新增或者刪除 (數據條數變化)

同樣的條件, 第1次和第2次讀出來的記錄數不一樣

例子:

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

Java代碼   收藏代碼
  1. con1 = getConnection();  
  2. Select * from employee where salary =1000;  
共讀取10條記錄 

這時另一個事務向employee表插入了一條員工記錄,工資也為1000 
Java代碼   收藏代碼
  1. con2 = getConnection();  
  2. Insert into employee(empId,salary) values("Lili",1000);  
  3. con2.commit();  
事務1再次讀取所有工資為1000的員工 
Java代碼   收藏代碼
  1. //con1  
  2. select * from employee where salary =1000;  
共讀取到了11條記錄,這就像產生了幻讀。 
 
 
 原文鏈接:http://blog.csdn.net/yuxin6866/article/details/52649048
 
 
 
 


免責聲明!

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



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