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/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/53956/viewspace-2128280/