serializable隔離級別下事務特性的幾個小測試

oliseh發表於2016-11-11

oracle裡事務的隔離級別主要有以下三類:
Read Committed
Serializable
Read-only


隔離級別可以在會話、事務兩個級別上進行設定:
———會話級別設定
alter session set isolation_level=read committed; 
alter session set isolation_level=serializable;


注:read only無法在會話級別進行設定


———事務級別設定
set transaction isolation level read committed; 
set transaction isolation level serializable;
set transaction read only;

其中Read Committed是預設的也是最常用的。
後兩個雖然用的不多,但研究一下也挺有意思,Serializable與Read-only的區別僅在於前者支援DML,關於它們的詳細區別可以參考我的另一篇文章<<設定transaction的讀寫屬性與隔離級別>>:http://blog.itpub.net/53956/viewspace-1286315/
下文以Serializable為例,揭示了該隔離級別下事務所具備的一些特質


先來看看會話級的設定:


////////////////////////////
// alter session set isolation_level=serializable
////////////////////////////
場景1:在設定session 1的隔離級別為serializable後馬上查詢表,然後在session 2裡再執行更新
select * from t1110_1;
        ID
----------
        22
        33
        89


---session 1: app01/app01
alter session set isolation_level=serializable;


select * from t1110_1;    <---在session 2執行update前先在session 1執行一次select
        ID
----------
        22
        33
        89
        
---session 2: app01/app01
SQL> update t1110_1 set id=189 where id=89;


SQL> commit;


Commit complete.


SQL> select * from t1110_1;


        ID
----------
        22
        33
       189


---session 1: app01/app01       
SQL> select * from t1110_1;   <---session 1看到的結果與第一次查詢結果一致


        ID
----------
        22
        33
        89


rollback;


SQL> select * from t1110_1;    <---rollback後能看到最新的更新結果(rollback表示新的事務已經開始)


        ID
----------
        22
        33
       189


---session 2: app01/app01
SQL> update t1110_1 set id=133 where id=33;   <---再次更新


1 row updated.


SQL> commit;


Commit complete.


---session 1: app01/app01       
SQL> select * from t1110_1;    <---因為session 1自從上一次select後並未執行commit或rollback,所以看到的還是上一次的結果


        ID
----------
        22
        33
       189


SQL> commit;   <---執行了commit後標誌這接下來的select能夠訪問到最新修改的結果了


Commit complete.


SQL> select * from t1110_1;       


        ID
----------
        22
       133
       189 


場景2:在設定session 1的隔離級別為serializable後不馬上查詢表,而是等到session 2首次更新後再發起查詢
select * from t1110_1;
        ID
----------
        22
        33
        89


---session 1: app01/app01
alter session set isolation_level=serializable;  <---此處僅設定session屬性,不執行查詢


---session 2: app01/app01
SQL> update t1110_1 set id=189 where id=89;


SQL> commit;


Commit complete.


SQL> select * from t1110_1;


        ID
----------
        22
        33
       189


---session 1: app01/app01       
SQL> select * from t1110_1;   <---session 1能看到最新的結果


        ID
----------
        22
        33
       189


---session 2: app01/app01
SQL> update t1110_1 set id=133 where id=33;   <---再次更新


1 row updated.


SQL> commit;


Commit complete.


---session 1: app01/app01       
SQL> select * from t1110_1;    <---因為session 1自從上一次select後並未執行commit或rollback,所以看到的還是與上一次一致的結果


        ID
----------
        22
        33
       189


SQL> commit;   <---執行了commit後標誌著接下來的select能夠訪問到最新修改的結果了


Commit complete.


SQL> select * from t1110_1;       


        ID
----------
        22
       133
       189


場景3:多張表情況下的表現
已存在的表:t1110_1、t1110_2
測試過程中將建立的新表:t1110_4


SQL> select * from t1110_1;
        ID
----------
      1122
       133
       189


SQL> select * from t1110_2;


        ID
----------
       999
       888


---session 1:app01/app01
              
SQL> alter session set isolation_level=serializable;


Session altered.


select * from t1110_1;
        ID
----------
      1122
       133
       189


---session 2:app01/app01
SQL> select * from t1110_1;


        ID
----------
      1122
       133
       189


SQL> select * from t1110_2;


        ID
----------
       999
       888


SQL> update t1110_1 set id=11122 where id=1122;


1 row updated.
 
SQL> commit;


Commit complete.


SQL> select * from t1110_1;


        ID
----------
     11122
       133
       189


---session 1
SQL> select * from t1110_1;   <---與首次查詢結果一致


        ID
----------
      1122
       133
       189
       
---session 2
SQL> update t1110_2 set id=9999 where id=999;


1 row updated.


SQL> commit;


Commit complete.


SQL> select * from t1110_2;


        ID
----------
      9999
       888
       
---session 1
SQL> select * from t1110_2;    <---查到修改前的結果


        ID
----------
       999
       888


---session 2
SQL> create table t1110_4 (id number);   <---建立新表並插入記錄


Table created.


SQL> insert into t1110_4 values(9900);


1 row created.


SQL> commit;


Commit complete.


select * from t1110_4;


        ID
----------
      9900


---session 1


SQL> select * from t1110_4;     <----雖然t1110_4是在session 1設定serializable隔離級別之後建立的,還是能看到表結構,但看不到資料


no rows selected      


接著看下事務級的設定

////////////////////////////
// set transaction isolation level serializable
////////////////////////////
SQL> select * from t1110_1;


        ID
----------
        22
        33
        89


---session 1:app01/app01 
set transaction isolation level serializable;  


SQL> select * from t1110_1;


        ID
----------
        22
        33
        89


---session 2:app01/app01           
SQL> update t1110_1 set id=122 where id=22;


1 row updated.


SQL> commit;


Commit complete.


SQL> select * from t1110_1;


        ID
----------
       122
        33
        89


---session 1:app01/app01 
SQL> select * from t1110_1;   <---與首次執行的結果相同


        ID
----------
        22
        33
        89


rollback;


SQL> select * from t1110_1;   <---rollback後開始新的session


        ID
----------
       122
        33
        89


---session 2:app01/app01 進行第二次更新操作
SQL> update t1110_1 set id=133 where id=33;


SQL> commit;


Commit complete.


SQL> select * from t1110_1;


        ID
----------
       122
       133
        89


---session 1:app01/app01
SQL> select * from t1110_1;    <--- 能看到session 2第二次更新後的結果


        ID
----------
       122
       133
        89


set transaction isolation level serializable;     <---再次設定成serializable隔離級別


---session 2:app01/app01 進行三次更新操作
SQL> update t1110_1 set id=189 where id=89;


1 row updated.


SQL> commit;


Commit complete.


SQL> select * from t1110_1;


        ID
----------
       122
       133
       189


---session 1:app01/app01
SQL> select * from t1110_1;   <---看到的還是session 2第二次更新後的結果
        ID
----------
       122
       133
        89


SQL> rollback;


Rollback complete.


SQL> select * from t1110_1;   <---rollback後能看到最新的更新結果


        ID
----------
       122
       133
       189

總結
(1) 會話級設定serializable隔離級別

會話級別上如果將隔離級別設定成了serializable,那麼在這個會話中對錶發起的第一次查詢能查到最近一次commit後的結果,後續發起的查詢查到的結果均與第一次查詢的結果保持一致,其原理應該是記錄了首次查詢期間的SCN,後面如果不commit或者rollback,那麼將一直以這個SCN作為查詢的高水位只返回小於等於此SCN時刻發生的已提交的修改,以上結論只適用於DML操作,對於在SCN時刻之後發生的DDL操作仍能被查到。
當執行commit或者rollback後,意味著新事務的開始,會以當時的SCN作為新的查詢高水位去獲取最新的修改結果。由於serializable的隔離級別設定在session級別,所以只要還在session理,每開始一個新事務就會自動繼承serializable的隔離屬性,不必為每個事務顯式的設定serializable隔離級別


(2) 事務級設定serializable隔離級別

Transaction級別上如果將隔離級別設定成了serializable,那麼當執行了rollback或者commit終止了Transaction後,若要再次進入serializable的隔離級別就必須重新執行set transaction isolation level serializable進行設定。其它特性同會話級設定,不再贅述




        

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/53956/viewspace-2128280/,如需轉載,請註明出處,否則將追究法律責任。

相關文章