ITPub博客

首页 > 数据库 > Oracle > serializable隔离级别下事务特性的几个小测试

serializable隔离级别下事务特性的几个小测试

原创 Oracle 作者:oliseh 时间:2016-11-11 08:34:37 0 删除 编辑

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/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
不仅仅专注Oracle database技术, member of SHOUG

注册时间:2014-04-06

  • 博文量
    128
  • 访问量
    1616693