√: 可能出现 ×: 不会出现
隔离级别 |
脏读 |
不可重复读 |
幻读 |
Read uncommitted |
√ |
√ |
√ |
Read committed |
× |
√ |
√ |
Repeatable read |
× |
× |
√ |
Serializable |
× |
× |
× |
脏读:事务A读到事务B未提交的修改后数据;隔离级别Read uncommitted会出现这种情况。具体描述就是事务T1更新了一行记录,还未提交所做的修改,这个T2读取了更新后的数据,然后T1执行回滚操作,取消刚才的修改,所以T2所读取的行就无效,也就是脏数据。
不可重复读:事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。这就是不可重复读。
当隔离级别设置为Read committed时,避免了脏读,但是可能会造成不可重复读。
当隔离级别设置为Repeatable read时,可以避免不可重复读。当事务A正在读取某条记录时(即事务开始读取该记录),事务B不可能对该记录进行修改,插入新记录或修改其他记录不影响。
虽然Repeatable read避免了不可重复读,但还有可能出现幻读。
幻读:事务A读取一条指定where条件的语句,返回结果集。此时事务B插入一行新记录,恰好满足事务A的where条件。然后事务A使用相同的条件再次查询,结果集中可以看到事务B插入的记录,这条新记录就类似产生幻觉(一个事务按相同的查询条件查询之前检索过的数据,却发现检索出来的结果集条数变多或者减少(由其他事务插入、删除的),类似产生幻觉)。
隔离级别Serializable是最高级别,避免发生上述三种情况。
常见设置隔离级别语句:
SET TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE];
ORACLE只支持下面两种:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Oracle中的隔离级别及实现机制:
Oracle数据库支持READ COMMITTED 和SERIALIZABLE这两种事务隔离级别。所以Oracle不支持脏读,即Oracle中不允许一个会话读取其他事务未提交的数据修改结果,从而防止了由于事务回滚发生的读取不正确。
Oracle回滚段,在修改数据记录时,会把这些记录被修改之前的结果存入回滚段或撤销段中。Oracle读取操作不会阻碍更新操作,更新操作也不会阻碍读取操作,这样在Oracle中的各种隔离级别下,读取操作都不会等待更新事务结束,更新操作也不会因为另一个事务中的读取操作而发生等待,这也是Oracle事务处理的一个优势所在。
Oracle缺省的配置是Read Committed隔离级别(也称为语句级别的隔离),在这种隔离级别下,如果一个事务正在对某个表执行 DML操作,而这时另外一个会话对这个表的记录执行读取操作,则Oracle会去读取回滚段或撤销段中存放的更新之前的记录,而不会像SQL Server一样等待更新事务的结束。
Oracle的Serializable隔离级别(也称为事务级别的隔离),事务中的读取操作只能读取这个事务开始之前已经提交的数据结果。如果在读取时,其他事务正在对记录执行修改,则Oracle就会在回滚段或撤销段中去寻找对应的原来未经修改的记录(而且是在读取操作所在的事务开始之前存放于回滚段或撤销段的记录),这时读取操作也不会因为相应记录被更新而等待。
ORACLE怎么实现隔离级别Repeatable read?
虽然不能用语句SET TRANSACTION ISOLATION LEVEL 来设置,但实际上 SELECT FOR UPDATE可以实现这个目的。
举例说明:会话A执行如下语句之后:
SELECT * FROM SCOTT.EMP WHERE ENAME='SMITH' FOR UPDATE; (注意不执行COMMIT/ROLLBACK;)
会话B执行语句UPDATE SCOTT.EMP SET ENAME='SMITH000' WHERE ENAME='SMITH'; 就会一直等待会话A释放锁(即COMMIT/ROLLBACK;的执行),因此会话B在会话A提交或回滚事务前无法执行后续的语句(包括COMMIT/ROLLBACK;语句)。这一点类似MS SQL SERVER的默认隔离级别(Repeatable read)