√: 可能出現 ×: 不會出現
隔離級別 |
臟讀 |
不可重復讀 |
幻讀 |
Read uncommitted |
√ |
√ |
√ |
Read committed |
× |
√ |
√ |
Repeatable read |
× |
× |
√ |
Serializable |
× |
× |
× |
臟讀:事務A讀到事務B未提交的修改后數據;隔離級別Read uncommitted會出現這種情況。具體描述就是事務T1更新了一行記錄,還未提交所做的修改,這個T2讀取了更新后的數據,然后T1執行回滾操作,取消剛才的修改,所以T2所讀取的行就無效,也就是臟數據。
不可重復讀:事務A事先讀取了數據,事務B緊接了更新了數據,並提交了事務,而事務A再次讀取該數據時,數據已經發生了改變。這就是不可重復讀。
當隔離級別設置為Read committed時,避免了臟讀,但是可能會造成不可重復讀。
當隔離級別設置為Repeatable read時,可以避免不可重復讀。當事務A正在讀取某條記錄時(即事務開始讀取該記錄),事務B不可能對該記錄進行修改,插入新記錄或修改其他記錄不影響。
雖然Repeatable read避免了不可重復讀,但還有可能出現幻讀。
幻讀:事務A讀取一條指定where條件的語句,返回結果集。此時事務B插入一行新記錄,恰好滿足事務A的where條件。然后事務A使用相同的條件再次查詢,結果集中可以看到事務B插入的記錄,這條新記錄就類似產生幻覺(一個事務按相同的查詢條件查詢之前檢索過的數據,卻發現檢索出來的結果集條數變多或者減少(由其他事務插入、刪除的),類似產生幻覺)。
隔離級別Serializable是最高級別,避免發生上述三種情況。
常見設置隔離級別語句:
SET TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE];
ORACLE只支持下面兩種:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Oracle中的隔離級別及實現機制:
Oracle數據庫支持READ COMMITTED 和SERIALIZABLE這兩種事務隔離級別。所以Oracle不支持臟讀,即Oracle中不允許一個會話讀取其他事務未提交的數據修改結果,從而防止了由於事務回滾發生的讀取不正確。
Oracle回滾段,在修改數據記錄時,會把這些記錄被修改之前的結果存入回滾段或撤銷段中。Oracle讀取操作不會阻礙更新操作,更新操作也不會阻礙讀取操作,這樣在Oracle中的各種隔離級別下,讀取操作都不會等待更新事務結束,更新操作也不會因為另一個事務中的讀取操作而發生等待,這也是Oracle事務處理的一個優勢所在。
Oracle缺省的配置是Read Committed隔離級別(也稱為語句級別的隔離),在這種隔離級別下,如果一個事務正在對某個表執行 DML操作,而這時另外一個會話對這個表的記錄執行讀取操作,則Oracle會去讀取回滾段或撤銷段中存放的更新之前的記錄,而不會像SQL Server一樣等待更新事務的結束。
Oracle的Serializable隔離級別(也稱為事務級別的隔離),事務中的讀取操作只能讀取這個事務開始之前已經提交的數據結果。如果在讀取時,其他事務正在對記錄執行修改,則Oracle就會在回滾段或撤銷段中去尋找對應的原來未經修改的記錄(而且是在讀取操作所在的事務開始之前存放於回滾段或撤銷段的記錄),這時讀取操作也不會因為相應記錄被更新而等待。
ORACLE怎么實現隔離級別Repeatable read?
雖然不能用語句SET TRANSACTION ISOLATION LEVEL 來設置,但實際上 SELECT FOR UPDATE可以實現這個目的。
舉例說明:會話A執行如下語句之后:
SELECT * FROM SCOTT.EMP WHERE ENAME='SMITH' FOR UPDATE; (注意不執行COMMIT/ROLLBACK;)
會話B執行語句UPDATE SCOTT.EMP SET ENAME='SMITH000' WHERE ENAME='SMITH'; 就會一直等待會話A釋放鎖(即COMMIT/ROLLBACK;的執行),因此會話B在會話A提交或回滾事務前無法執行后續的語句(包括COMMIT/ROLLBACK;語句)。這一點類似MS SQL SERVER的默認隔離級別(Repeatable read)