隔离级别 |
脏读 |
不可重复读 |
幻像读 |
READ UNCOMMITTED |
允许 |
允许 |
允许 |
READ COMMITTED |
|
允许 |
允许 |
REPEATABLE READ |
|
|
允许 |
SERIALIZABLE |
|
|
|
READ UNCOMMITTED 提供非阻塞读 允许脏读。
READ COMMITTED 事务只能读取数据库中已经提交的数据,所以没有脏读,但可能有不可重复读和幻读(与事务早期相比,查询不光能看到其它提交事务更新的行,还能看到新插入的行),还有一点就是,如果在一条语句中查询了多行,除Oracle以外的其它数据库都可能 “退化”成像脏读一样,并且写阻塞读,产生等待,并且数据是错误的。
REPEATABLE READ(可重复读) 保证读一致(read-consistent) 在非Oracle数据库中
为达可重复读,需要阻塞一个事务,并且顺序执行两个事务,这是使用共亨锁来实现,这样,读会阻塞写,且写会阻塞读,影响并发性,而且会产生死锁。
SERIALIZABLE 就像一个用户一样地操作
上而说的都是非Oracle存在的缺点,在Oracle中有三个级别
Oracle实现原理:得用undo段实现数据多版本,来得到读一致性,并且支持非阻塞读,高并发性,鱼和熊掌兼得。
1)、READ COMMITTED 结果级别非上而提到的级别,不会脏读,不可重复读,幻读,这是Oracle默认的级别。
2)、READ ONLY(只读) 相当于无法在SQL完成任何修改的REPEATABLE READ或
SERIALIZABLE,唯一的区别是READ ONLY事务不行修改,因此没有去3)点中的ORA-08177错误,但他不能防止其它事务的修改,如果undo太小的话,有可能重用undo段,并导致ORA-15555:snaphot too old错误,所以设置足够大的undo大小。
3)、SERIALIZABLE 原本是语句级的读一致性,扩展到事务级,结果并非相对开始的那个时间点一致,而是在事务开始的那一刻就固定了,这是有代价的,只要你试图更新某一行,而这行自事务开始后已经修改,你就会得到ORA-08177 cant't serialize access for this transaction错误(同一块的所有行修改都可能导致这个错误)为避免这个错误,可以用select ... for update,实现串行访问,但这也并不意味是SERIALIZALBLE等同与串行顺序并且总能得到相同的结果。
时间 |
会话1执行 |
会话2执行 |
T1 |
alter session set isolation =_level = serializable |
|
T2 |
|
alter session set isolation =_level = serializable |
T3 |
Insert into a select count(*) from b |
|
T4 |
|
Insert into a select count(*) from b |
T5 |
commit |
|
T6 |
|
commit |
结果表a和表b都有一个为0的行
注意以sys用户或sysdba连接的用户不能有READ ONLY或SERIALIZABLE的事务。