天天看點

Spring - 事務之隔離級别

事務的第二個次元就是隔離級别(isolation level)。隔離級别定義了一個事務可能受其他并發事務影響的程度。 

(1)并發事務引起的問題

在典型的應用程式中,多個事務并發運作,經常會操作相同的資料來完成各自的任務。并發雖然是必須的,但可能會導緻以下的問題。

  • 髒讀(Dirty reads)——髒讀發生在一個事務讀取了另一個事務改寫但尚未送出的資料時。如果改寫在稍後被復原了,那麼第一個事務擷取的資料就是無效的。
  • 不可重複讀(Nonrepeatable read)——不可重複讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的資料時。這通常是因為另一個并發事務在兩次查詢期間進行了更新。
  • 幻讀(Phantom read)——幻讀與不可重複讀類似。它發生在一個事務(T1)讀取了幾行資料,接着另一個并發事務(T2)插入了一些資料時。在随後的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄。

不可重複讀與幻讀的差別

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

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

例如:在事務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

//con1  
select salary from employee empId ="Mary";      

在一個事務中前後兩次讀取的結果并不一緻,導緻了不可重複讀。

幻讀的重點在于新增或者删除: 

同樣的條件,第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的員工

//con1  
select * from employee where salary =1000;      

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

從總的結果來看,似乎不可重複讀和幻讀都表現為兩次讀取的結果不一緻。但如果你從控制的角度來看,兩者的差別就比較大。 

對于前者,隻需要鎖住滿足條件的記錄。 

(2)隔離級别