Oracle事务的隔离级别有2总, Read Commitment, Serializable, Read Only (另外还有2种事务隔离级别,Read Uncommitted, Repatable Read,Oracle没有单独提供.)
Read Only, 看名字就比较简单,在此我们不做讨论,下面主要分析一下Read Commitment, Serializable.
一句话描述:
Read Commitment: 读取在语句开始时已经提交的, 修改冲突通过写一致性来解决数据的一致性.
Serializable: 读取在事务开始时已经提交的. 修改冲突确保先提交的成功,后修改的回滚.
比较细节
不同点
读一致性 | 写冲突 | |
Read Commitment | 如果事务进行过程中,有数据在别的事务里面提交了,可以立即被当前事务读取到. | 先修改的可以正常提交,后修改的必须等到先修改提交之后.然后通过写一致性来重启事务 |
Serializable: | 事务开始后,其他事务的所有修改对当前事务没有任何影响 | 后修改数据的事务同样会被阻塞,但是当阻塞解除提交时会出现ORA-08177异常. (ORA-08177: can't serialize access for this transaction) |
相同点
读一致性 | 写冲突 | |
Read Commitment | 只有提交后的数据才会被读取,都不会读取脏数据. | 后修改数据的事务都会被阻塞,无法提交. |
Serializable: |
实验过程
下面的2个实验,比较了Oracle所支持的事务隔离模式, 在读取和修改数据时的详细区别. 如何切换数据库的隔离模式,可以参考下面的语句.
ALTER SESSION SET ISOLATION_LEVEL = READ COMMITTED;
ALTER SESSION SET ISOLATION_LEVEL = serializable;
- 数据初始化
下面的2个实验,在
开始前需要使用上面的初始化脚本Reset数据.
DROP TABLE XXRPTH.TEST;
CREATE TABLE XXRPTH.TEST
(
NAME VARCHAR(10),
VALUE NUMBER(22)
);
insert into test values('lilao_1', 1);
insert into test values('lilao_2', 2);
insert into test values('lilao_3', 3);
commit;
- 实验#1: 读取变化数据的区别
关键比较点,已经标红高亮
时间 | 事务1 | 事务2 | Read Commitment | Serializable: |
t1 | savepoint aaa; | 显示开启事务1 | ||
t2 | savepoint bbb; | 显示开启事务2 | ||
t3 | update test set value=value+10 ; | |||
t4 | select count(*) from test where value>10; | 结果是0(读可提交) | 结果是0 | |
t5 | commit; | |||
t6 | select count(*) from test where value>10; | 结果是3(幻象读,和t4时间读取的记录条数不一样了) | 结果是0 | |
t7 | commit; | |||
t8 | select * from test; | NAME VALUE ---------- ---------- lilao_1 11 lilao_2 12 lilao_3 13 | NAME VALUE ---------- ---------- lilao_1 11 lilao_2 12 lilao_3 13 |
- 实验#2: 写冲突的区别
时间 | 事务1 | 事务2 | Read Commitment | Serializable: |
t1 | savepoint aaa; | 显示开启事务1 | ||
t2 | savepoint bbb; | 显示开启事务2 | ||
t3 | update test set value=value+10 ; | |||
t4 | select count(*) from test where value>10; | 结果是0(读可提交) | 结果是0 | |
t5 | update test set value=value+100; | |||
t6 | commit; | 事务2提交时,事务1会抛出异常 ORA-08177: can't serialize access for this transaction | ||
t7 | select * from test; | NAME VALUE ---------- ---------- lilao_1 111 lilao_2 112 lilao_3 113 | NAME VALUE ---------- ---------- lilao_1 1 lilao_2 2 lilao_3 3 | |
t8 | commit; | 虽然事务1在T6时,抛出异常,但是事务并未终止. 所以T7时间没有查询到事务2的修改 | ||
t9 | select * from test; | NAME VALUE ---------- ---------- lilao_1 111 lilao_2 112 lilao_3 113 | NAME VALUE ---------- ---------- lilao_1 11 lilao_2 12 lilao_3 13 |