事務的第二個次元就是隔離級别(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條記錄,這就産生了幻像讀。
從總的結果來看,似乎不可重複讀和幻讀都表現為兩次讀取的結果不一緻。但如果你從控制的角度來看,兩者的差別就比較大。
對于前者,隻需要鎖住滿足條件的記錄。