Oracle采用MVCC技术进行事务隔离,它只支持2种隔离级别,读已提交和可串行化
,设置其他隔离级别会报错
。这种基于MVCC的
可串行化也被称为
SNAPSHOT ISOLATION(SI)
。就像
SNAPSHOT的字面意思一样,MVCC像是
给每个事务保留一个快照,对于数据的读取可以不受其他事务的影响。
读已提交和可串行化的区别在于
SNAPSHOT采取的时点,
前者在SQL执行时,后者在事务开始时。下面参照之前的做法也对Oracle事务进行实测。
1. 测试环境
OS:RHEL6
DBMS:Oracle 11g
2. 测试结果
读已提交:
OK(**):基于更新前的数据,即看到是查询时的快照
等待(*): 如果先行的SQL提交,则基于更新后的数据,否则基于原来的数据
注:黄色代表和SQL Server 的READ_COMMITTED_SNAPSHOT=ON时的读已提交不同的地方
从上面的表可以看出,Oracle 的 读已提交比SQL Server的 READ_COMMITTED_SNAPSHOT=ON时的读已提交 基本上差不多,但处理插入时阻塞的可能性更小。
可串行化:
OK(***):基于更新前的数据,查询看到的是事务开始时的快照
等待(*): 如果先行的SQL提交,则基于更新后的数据,否则基于原来的数据
等待(**):如果先行的SQL提交,则报更新冲突的错误,"ORA-08177: 无法连续访问此事务处理"
注:黄色代表和读已提交不同的地方
3. Oracle的 串行化(SI) 和真正串行化的区别
Oracle的串行化(SI)其实等同于SQL Server的SNAPSHOT,它满足SQL标准对可串行化的要求,但并不是真正的可串性化。下面用一个例子来说明。
SI下,2个事务按下面的顺序交替执行,可以执行成功。
1) 事务1:select * from tb1;
2) 事务2:select * from tb1;
3) 事务1:insert into tb1 values(5,'a');
4) 事务2:insert into tb1 values(6,'a');
5) 事务1:commit;
6) 事务2:commit;
但是这不符合真正的串行化。如果2个事务按照 事务1->事务2 的顺序串行执行, 在2)中事务2应该能看到3)事务1插入的数据,这是不可能的;反之 事务2->事务1 亦然。
*)详细测试方法请参考:
并发事务下各数据库外部表现实测之一(SQL Server篇)
http://blog.chinaunix.net/uid-20726500-id-3883105.html
1. 测试环境
OS:RHEL6
DBMS:Oracle 11g
2. 测试结果
读已提交:
| 先执行SQL\后执行SQL |
同一行查询 | 非同行查询 | 整表查询 | 同一行插入 | 非同行插入 | 同一行更新 | 非同行更新 | 整表更新 | 同一行删除 | 非同行删除 | 整表删除 |
| 单行查询 | OK | OK | OK | 主键冲突 | OK | OK | OK | OK | OK | OK | OK |
| 整表查询 | OK | OK | OK | 主键冲突 | OK | OK | OK | OK | OK | OK | OK |
| 插入 | OK(**) |
OK | OK(**) |
等待(*) | OK | OK(**) | OK | OK(**) | OK(**) | OK | OK(**) |
| 单行更新 | OK(**) |
OK | OK(**) |
主键冲突 | OK | 等待(*) | OK | 等待(*) | 等待(*) | OK | 等待(*) |
| 整表更新 | OK(**) |
OK |
OK(**) |
主键冲突 | OK | 等待(*) | OK | 等待(*) | 等待(*) | OK | 等待(*) |
| 单行删除 |
OK(**) |
OK | OK(**) |
等待(*) | OK | 等待(*) | OK | 等待(*) | 等待(*) | OK | 等待(*) |
| 整表删除 | OK(**) |
OK | OK(**) |
等待(*) | OK | 等待(*) | OK | 等待(*) | 等待(*) | OK | 等待(*) |
等待(*): 如果先行的SQL提交,则基于更新后的数据,否则基于原来的数据
注:黄色代表和SQL Server 的READ_COMMITTED_SNAPSHOT=ON时的读已提交不同的地方
从上面的表可以看出,Oracle 的 读已提交比SQL Server的 READ_COMMITTED_SNAPSHOT=ON时的读已提交 基本上差不多,但处理插入时阻塞的可能性更小。
可串行化:
| 先执行SQL\后执行SQL |
同一行查询 | 非同行查询 | 整表查询 | 同一行插入 | 非同行插入 | 同一行更新 | 非同行更新 | 整表更新 | 同一行删除 | 非同行删除 | 整表删除 |
| 单行查询 | OK | OK | OK | 主键冲突 | OK | OK | OK | OK | OK | OK | OK |
| 整表查询 | OK | OK | OK | 主键冲突 | OK | OK | OK | OK | OK | OK | OK |
| 插入 | OK(***) |
OK | OK(***) |
等待(*) | OK | OK(***) | OK | OK(***) | OK(***) | OK | OK(***) |
| 单行更新 |
OK(***) |
OK | OK(***) |
主键冲突 | OK | 等待(**) | OK | 等待(**) | 等待(**) | OK | 等待(**) |
| 整表更新 |
OK(***) |
OK |
OK(***) |
主键冲突 | OK | 等待(**) | OK | 等待(**) | 等待(**) | OK | 等待(**) |
| 单行删除 |
OK(***) |
OK | OK(***) |
等待(*) | OK | 等待(**) | OK | 等待(**) | 等待(**) | OK | 等待(**) |
| 整表删除 | OK(***) |
OK | OK(***) |
等待(*) | OK | 等待(**) | OK | 等待(**) | 等待(**) | OK | 等待(**) |
等待(*): 如果先行的SQL提交,则基于更新后的数据,否则基于原来的数据
等待(**):如果先行的SQL提交,则报更新冲突的错误,"ORA-08177: 无法连续访问此事务处理"
注:黄色代表和读已提交不同的地方
3. Oracle的 串行化(SI) 和真正串行化的区别
Oracle的串行化(SI)其实等同于SQL Server的SNAPSHOT,它满足SQL标准对可串行化的要求,但并不是真正的可串性化。下面用一个例子来说明。
SI下,2个事务按下面的顺序交替执行,可以执行成功。
1) 事务1:select * from tb1;
2) 事务2:select * from tb1;
3) 事务1:insert into tb1 values(5,'a');
4) 事务2:insert into tb1 values(6,'a');
5) 事务1:commit;
6) 事务2:commit;
但是这不符合真正的串行化。如果2个事务按照 事务1->事务2 的顺序串行执行, 在2)中事务2应该能看到3)事务1插入的数据,这是不可能的;反之 事务2->事务1 亦然。
*)详细测试方法请参考:
并发事务下各数据库外部表现实测之一(SQL Server篇)
http://blog.chinaunix.net/uid-20726500-id-3883105.html