一、 多版本并发访问控制
Oracle 能够自动地实现一个查询的读一致性(read consistency),即一个查询所获得的数据来自同一时间点(single point in time)(这也被称为语句级读一致性(statement-level read consistency))。Oracle 还能令一个事务内的所有查询都具备读一致性(即事务级读一致性(transaction-level read consistency))。
Oracle 利用回滚段(rollback segment)中的信息生成一个能保证一致性的数据视图。回滚段内保存了未提交或最近提交的事务中所修改数据的原值。图展示了 Oracle 如何利用回滚段实现语句级的读一致性。
在查询开始执行时,将记录当前的系统变化编号(system change number,SCN)。在图中,记录的系统变化编号为 10023。当查询进行扫描时,只会使用有效的(observed)数据块。如果某个数据块内的数据被修改过(即数据块的 SCN 晚于查询开始执行时记录的SCN),Oracle 将使用回滚段中的信息重建此数据块,并以重建的数据块替代被修改的数据块供查询使用。因此,查询的结果集只包含查询开始执行时就已经提交的数据。在查询执行时,其他事务修改的数据对此查询来说是无效的,这保证了每个查询都能 得到满足一致性的数据。
二、语句级读一致性
Oracle 强制实现语句级读一致性(statement-level read consistency)。这保证了单一查询的结果集来自一个时间点——即查询开始执行的时间。因此,一个查询的结果集永远不会包含脏数据及此查询执行时其他事务提交的数据。在一个查询执行期间,只有在查询执行前提交的数据对此查询才是可见的。查询无法看到其开始执行后提交的数据。
任何一个查询都能得到满足一致性的结果集,这保证了用户无需额外操作就能确保数据一致性。SELECT,使用子查询的 INSERT,及包含显式或隐式查询的 UPDATE 或 DELETE 语句,都能够保证数据一致性。上述语句通过一个查询(query)来得到她们所需的满足一致性的结果集(分别使用 SELECT,INSERT,UPDATE 或 DELETE 语句)。
三、事务级读一致性
Oracle 还能够实现事务级读一致性(transaction-level read consistency)。当一个事务运行在串行化模式(serializable mode)下时,则事务内所有数据访问均反映的是事务开始时的数据状态。即事务内的所有查询对某个时间点来说具备一致性,但是运行在串行化模式下的事务能够看到事务自身对数据所作的修改。事务级的读一致性能够保证可重复读取(repeatable read)并可阻止出现不存在读取(phantomread)。
四、RAC 环境下的读一致性
RAC 系统采用缓存对缓存(cache-to-cache)的数据块传输机制(此技术被称为 Cache Fusion)在实例间传输满足读一致性(read-consistent)的数据块镜像。RAC 系统通过高速度低延迟的内部连接(interconnect)实现上述数据传输,从而满足实例之间对数据块的请求。
五、Oracle 事务隔离级别
1、已提交读取
Oracle 默认使用的事务隔离级别。事务内执行的查询只能看到查询执行前(而非事务开始前)就已经提交的数据。Oracle 的查询永远不会读取脏数据(未提交的数据)。
Oracle 不会阻止一个事务修改另一事务中的查询正在访问的数据,因此在一个事务内的两个查询的执行间歇期间,数据有可能被其他事务修改。举例来说,如果一个事务内同一查询执行两次,可能会遇到不可重复读取(nonrepeatable read)或不存在读取(phantom)的现象。
2、串行化
串行化隔离的事务只能看到事务执行前就已经提交的数据,以及事务内 INSERT,UPDATE,及 DELETE 语句对数据的修改。串行化隔离的事务不会出现不可重复读取或不存在读取的现象。
3、只读模式
只读事务只能看到事务执行前就已经提交的数据,且事务中不能执行 INSERT,UPDATE,及 DELETE 语句。
六、设置隔离级别
应用程序的设计开发者及数据库管理员可以依据应用程序的需求及系统负载(workload)而为不同的事务选择不同的隔离级别(isolation level)。用户可以在事务开始时使用以下语句设定事务的隔离级别:
1、 SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
2、SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3、SET TRANSACTION READ ONLY;
用户可以使用 ALTER SESSION 语句改变一个会话所有内事务的默认隔离级别:
1、ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE;
2、ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;
已提交读取隔离
Oracle 默认使用的隔离级别(isolation level)是已提交读取(read committed)隔离。这种程度的隔离适合在事务发生冲突的可能性较小的系统中使用。在这种隔离级别下,Oracle 能够保证事务内每个查询在执行期间都拥有一个唯一的数据视图,因此事务可能出现不可重复读取(nonrepeatable read)或不存在读取(phantom)的现象,但此时系统的数据处理能力较高。因此已提交读取隔离(read committed isolation)适合在事务发生冲突的可能性较小的系统中使用。
串行化隔离
符合以下特性的系统适合采用串行化隔离(serializable isolation)
1、数据量大,但事务短小,只会更新较少数据行的数据库
2、两个并发事务修改相同数据的概率较小
3、运行时间相对较长的事务只执行只读操作
区别:
我们可以参考以下场景来研究 Oracle 中的两种隔离级别:假设现有一组数据库表(或称为一组数据集),一系列读取表数据的查询,以及一组在任意时间提交的事务。如果一个数据库操作(一个查询或一个事务)中所有读取返回的数据是由同一组已提交事务写入的,我们就称此操作满足事务集数据一致性(transaction set consistent)。相反,当一个数据库操作内的不同读取反映了不同事务集对数据的修改,此操作就不满足事务集数据一致性。换句话说,一个不满足事务集数据一致性的操作所看到的数据库的状态是由不同的已提交事务集决定的。
在已提交读取(read committed)隔离模式下,Oracle 能保证每个语句的事务集数据一致性。而在串行化(serializable)隔离模式下,Oracle能保证每个事务的事务集数据一致性。
在已提交读取隔离模式(read committed)及串行化隔离模式(serializable)下执行的事务都采用行级锁(row-level locking)技术,他们在更新被未提交的并发事务修改的数据行时都会发生等待--等待未提交的并发事务提交或撤销,并释放锁。如果未提交的并发事务进行了回滚,那么无论发生等待的事务运行在何种隔离模式下,都能修改之前被锁住的数据行,如同未提交的并发事务不存在一样。
当导致阻塞的事务(blocking transaction)[前文中提到的未提交的并发事务]提交并释放了锁后,运行在已提交读写模式下的等待事务就能够继续执行其中的更新操作。而运行在串行化模式下的等待事务将出现无法进行串行化访问(Cannot serialize access)错误,因为阻塞事务在串行化等待事务开始后更新了后者所存取的数据。