测试oracle10g 的IO隔离级别serializable

用sys用户给scott一个默认表空间
create tablespace lisx datafile '+DATA' ;
alter user scott default tablespace lisx ;

建测试表
create table dept
(deptno number(9),
deptname varchar2(20),
detail   varchar2(50)
);
insert into dept values(1,'业扩','新装增容') ;
insert into dept values(2,'账务','账务') ;
insert into dept values(3,'电费','电费') ;
insert into dept values(4,'质量','测试DBA打包') ;

commit ;

打开两个scott的会话
在会话1里面:
SQL> col deptname format a10 ;
SQL> col detail format a20 ;
SQL> select * from dept ;

    DEPTNO DEPTNAME   DETAIL
---------- ---------- --------------------
         1 业扩        新装增容
         2 账务         账务
         3 电费        电费
         4 质量        测试DBA打包

SQL> show user       
USER is "SCOTT"
SQL>
SQL>
SQL> update dept set detail='账务2222' where deptno=2 ;

1 row updated.

然后在会话2里:
SQL> set sqlprom 'SQL2>' ;
SQL2>
SQL2>col deptname format a10 ;
SQL2>col detail format a20 ;
SQL2>select * from dept ;

    DEPTNO DEPTNAME   DETAIL
---------- ---------- --------------------
         1 业扩        新装增容
         2 账务         账务
         3 电费        电费
         4 质量        测试DBA打包

SQL2>update dept set detail='账务33333' where deptno=2 ; 

如果第一个会话不提交,那么SQL2的修改会失败,一直等待前一个会话释放资源,形成了语句的死锁。

如果会话一提交,那么会话2也可以成功执行,但是因为修改的标准是参照最初的值,所以会覆盖会话1的修改结果。我们称之为不可重复读(Non Repeatable Read)
SQL>commit ;

Commit complete.

SQL2>commit ;

Commit complete.

下面在第二个会话设置
SQL2>alter session set isolation_level=serializable ;
我们看看设置IO隔离级别后的效果,主要是看看能否避免丢失修改。

SQL2>select * from dept ;

    DEPTNO DEPTNAME   DETAIL
---------- ---------- --------------------
         1 业扩        新装增容
         2 账务         账务33333
         3 电费        电费
         4 质量        测试DBA打包

在会话1里设置IO隔离级别
SQL>alter session set isolation_level=serializable ;

Session altered.

SQL> update dept set detail='44444' where deptno=2 ;

1 row updated.

先不提交,在会话2里面执行
SQL2>update dept set detail='55555' where deptno=2 ;
该修改会处于等待状态
 
然后提交会话1
SQL> commit ;

Commit complete.

会话2里面报错了:
SQL2>update dept set detail='55555' where deptno=2 ;
update dept set detail='55555' where deptno=2
       *
ERROR at line 1:
ORA-08177: can't serialize access for this transaction

因此通过设置会话1的隔离级别isolation_level=serializable,避免了其他会话的修改丢失。
理论上serializable还能避免幻影读,但是幻影读不太好实现。
SQL标准中定义了4中IO隔离级别
READ Uncommited
READ Commited  避免了脏读
Repeatable     避免了脏读,不可重复读
Serializable   避免了脏读,不可重复读,幻影读

但是ORACLE只有3中:
READ Commited
Serializable
Read Only

对于READ Uncommited,oracle无法模拟。
对于Repeatable,ORACLE可以通过悲观锁和乐观锁实现Repeatable
Read Only和Serializable的区别是对于丢失修改,前者是禁止修改,后者报错:
ORA-08177: can't serialize access for this transaction

 

 

 

 

 

 

 

 

posted @ 2010-03-22 17:23  李世侠  阅读(711)  评论(0编辑  收藏  举报