深究Oracle的隔离级别

http://www.cnblogs.com/jackal/archive/2011/02/14/1954231.html

多用户环境下的数据并发访问及数据一致性简介

在只有单一用户的数据库中,用户可以任意修改数据,而无需考虑同时有其他用户正在修改相同的数据。但在一个多用户数据库中,多个并发事务中包含的语句可能 会修改相同的数据。数据库中并发执行的事务最终应产生有意义且具备一致性的结果。因此在多用户数据库中,对数据并发访问(data concurrency)及数据一致性(data consistency)进行控制是两项极为重要的工作。

1、数据并发访问指多用户同时访问相同的数据。

2、数据一致性指系统中每个用户都能够取得具备一致性的数据,同时还能够看到自己或其他用户所提交的事务对数据的修改。

为了描述同时执行的多个事务如何实现数据一致性,数据库研究人员定义了被称为串行化处理(serializability)的事务隔离模型(transaction isolation model)。当所有事务都采取串行化的模式执行时,我们可以认为同一时间只有一个事务在运行(串行的),而非并发的。

以串行化模式对事务进行隔离的效果很好,但在此种模式下应用程序的效率将大大降低。将并行执行的事务完全隔离意味着即便当前只存在一个对表进行查询(query)的事务,其他事务也不能再对此表进行插入(insert)操作了。总之,为了满足实际要求,我们需要在事务的隔离程度与应用的性能之间找出一个平衡点。

Oracle 支持两种事务隔离级别(isolation level),使应用程序开发者在对事务进行控制时,既能保证数据的一致性,又能获得良好的性能。

需要防止的现象和事务隔离级别

ANSI/ISO SQL 标准(SQL92)定义了四种事务隔离级别(transaction isolation level),这四种隔离级别所能提供的事务处理能力各不相同。这些事务隔离级别是针对三种现象定义的,在并发事务执行时,需要阻止这三种现象 中的一种或多种发生。

三种需要阻止的现象(preventable phenomena)是:

1、脏读取(dirty read):一个事务读取了被其他事务写入但还未提交的数据。

2、不可重复读取(nonrepeatable read):一个事务再次读取其之前曾经读取过的数据时,发现数据已被其他已提交的事务修改或删除。

3、不存在读取(phantom read):事务按照之前的条件重新查询时,返回的结果集中包含其他已提交事务插入的满足条件的新数据。

SQL92 标准中定义了四个隔离级别,在各隔离级别中,允许发生上述三种需要阻止的现象中的一种或多种。详情见下表

现象 脏读取 不可重复读取 不存在读取
隔离级别
未提交读取(read uncommitted)
 
允许 允许 允许
已提交读取(read committed)
 
不允许
 
允许 允许
可重复读取(repeatable read)
 
不允许
 
不允许 允许
串行化(rerializable)
 
不允许
 
不允许 不允许


Oracle 支持三种事务隔离级别:已提交读取,串行化,以及 SQL92 中没有包含的只读模式(read-only mode)。已提交读取是 Oracle 默认使用的事务隔离级别。

Oracle 如何管理数据并发访问及数据一致性

Oracle 利用多版本一致性模型(multiversion consistency model),各种类型的锁及事务来管理多用户系统中的数据一致性(data consistency)。

多版本并发访问控制

Oracle 能够自动地实现一个查询的读一致性,即一个查询所获得的数据来自同一时间点(single point in time)(这也被称为语句级读一致性(statement-level read consistency))。Oracle 还能令一个事务内的所有查询都具备读一致性(即事务级读一致性(transaction-level read consistency))。

Oracle 利用回滚段中的信息生成一个能保证一致性的数据视图。回滚段内保存了未提交或最近提交的事务中所修改数据的原值。下图展示了 Oracle 如何利用回滚段实现语句级的读一致性。


在查询开始执行时,将记录当前的系统变化编号(system change number,SCN)。在中,记录的系统变化编号为 10023。当查询进行扫描时,只会使用有效的(observed)数据块。如果某个数据块内的数据被修改过(即数据块的 SCN 晚于查询开始执行时记录的 SCN),Oracle 将使用回滚段中的信息重建此数据块,并以重建的数据块替代被修改的数据块供查询使用。因此,查询的结果集只包含查询开始执行时就已经提交的数据。在查询执行时,其他事务修改的数据对此查询来说是无效的,这保证了每个查询都能得到满足一致性的数据。

语句级读一致性

Oracle 强制实现语句级读一致性(statement-level read consistency)。这保证了单一查询的结果集来自一个时间点——即查询开始执行的时间。因此,一个查询的结果集永远不会包含脏数据及此查询执行时其他事务提交的数据。在一个查询执行期间,只有在查询执行前提交的数据对此查询才是可见的。查询无法看到其开始执行后提交的数据。

任何一个查询都能得到满足一致性的结果集,这保证了用户无需额外操作就能确保数据一致性。SELECT,使用子查询的INSERT,及包含显式或隐式查询的UPDATEDELETE语句,都能够保证数据一致性。上述语句通过一个查询(query)来得到她们所需的满足一致性的结果集(分别使用SELECT,INSERT,UPDATE语句)。

语句是一个显式地查询,且其中可以包含嵌套查询(nested query)或连接操作(join operation)。语句中也能够使用嵌套查询。语句能够利用WHERE子句或子查询进行限制,只操作数据表内的部分数据行。

,及语句中包含的查询能够获得一致性的结果集。这些查询无法看到其所在 DML 语句对数据的修改。换句话说,这些查询只能看到其所在 DML 语句开始之前的数据。

TIPS:如果SELECT列表中存在 PL/SQL 函数,那么函数中包含的 SQL 语句将遵从其自身的语句级读一致性,而非其所在 SQL 的读一致性。例如,语句中的某个函数访问的表可能会在语句执行时被其他事务修改并提交。此函数每次执行时都将建立一个新的一致性视图(snapshot)。

事务一致性读

Oracle 还能够实现事务级读一致性(transaction-level read consistency)。当一个事务运行在串行化模式(serializable mode)下时,则事务内所有数据访问均反映的是事务开始时的数据状态。即事务内的所有查询对某个时间点来说具备一致性,但是运行在串行化模式下的事务能够看到事务自身对数据所作的修改。事务级的读一致性能够保证可重复读取并可阻止出现不存在读取。

RAC环境下的读一致性

RAC 系统采用缓存对缓存(cache-to-cache)的数据块传输机制(此技术被称为 Cache Fusion)在实例间传输满足读一致性(read-consistent)的数据块镜像。RAC 系统通过高速度低延迟的内部连接(interconnect)实现上述数据传输,从而满足实例之间对数据块的请求。

Oracle 事务隔离级别

Oracle 支持以下三种事务隔离级别(transaction isolation level)。

隔离级别 描述
已提交读取 Oracle 默认使用的事务隔离级别。事务内执行的查询只能看到查询执行前(而非事务开始前)就已经提交的数据。Oracle 的查询永远不会读取脏数据(未提交的数据)。

Oracle 不会阻止一个事务修改另一事务中的查询正在访问的数据,因此在一个事务内的两个查询的执行间歇期间,数据有可能被其他事务修改。举例来说,如果一个事务内同一查询执行两次,可能会遇到不可重复读取或不存在读取的现象。
 
串行化 串行化隔离的事务只能看到事务执行前就已经提交的数据,以及事务内INSERT,UPDATE,及DELETE语句对数据的修改。串行化隔离的事务不会出现不可重复读取或不存在读取的现象。
 
只读模式 只读事务只能看到事务执行前就已经提交的数据,且事务中不能执行INSERT,UPDATE,及DELETE语句。


应用程序的设计开发者及数据库管理员可以依据应用程序的需求及系统负载(workload)而为不同的事务选择不同的隔离级别(isolation level)。用户可以在事务开始时使用以下语句设定事务的隔离级别:

已提交读模式:SET TRANSACTION ISOLATION LEVEL=READ COMMITTED;

串行模式:SET TRANSACTION ISOLATION LEVEL= SERIALIZABLE;

只读模式:SET TRANSACTION= READ ONLY;

(经笔者实验以上命令在非sysdba用户下可以成功执行,sysdba下不能执行,待验证正确性)
如果在每个事务开始时都使用
SET TRANSACTION语句,将加重网络及处理器的负担。用户可以使用ALTER SESSION语句改变一个会话所有内事务的默认隔离级别:

1、ALTER SESSION SET ISOLATION_LEVEL SERIALIZABLE;

2、ALTER SESSION SET ISOLATION_LEVEL READ COMMITTED;

(无法设置会话级别的只读隔离模式)

已提交读取隔离

Oracle 默认使用的隔离级别(isolation level)是已提交读取(read committed)隔离。这种程度的隔离适合在事务发生冲突的可能性较小的系统中使用。在这种隔离级别下,Oracle 能够保证事务内每个查询在执行期间都拥有一个唯一的数据视图,因此事务可能出现不可重复读取或不存在读取的现象,但此时系统的数据处理能力较高。

串行化隔离

符合以下特性的系统适合采用串行化隔离(serializable isolation):

1、数据量大,但事务短小,只会更新较少数据行的数据库

2、两个并发事务修改相同数据的概率较小

3、运行时间相对较长的事务只执行只读操作

在串行化隔离下,并发事务对数据库进行修改时只能顺序执行。具体来说,在串行化隔离下,Oracle 在允许一个采用串行化隔离的事务修改某些数据行时,需要判断在此事务开始执行之前,其他所有事务对这些数据行的修改已经被提交。

为了实现上述判断,Oracle 在数据块内存储了相关的控制信息,用于记录此块内数据行中所包含的数据是已提交或未提交的。即数据块内记录了近期对本数据块内数据行进行了修改的所有事务及事务的状态。在一个数据块内能够保留多少这样的记录是由CREATE TABLEALTER TABLE语句中的INITRANS参数设定的。

有些情况下,Oracle 无法获得足够的历史信息来判断某个数据行是否被一个事务修改过。当大量事务在短时间内并发地修改同一数据块就会出现以上情况。用户可以为可能被多个事务同时更新相同数据块的表设置较大的值,以便避免上述情况。设置了较大的值后,Oracle 就能为每个数据块分配足够的空间来记录访问此数据块的事务的信息。

当一个串行化事务试图更新或删除数据,而这些数据在此事务开始后被其他事务修改并进行了提交,Oracle 将报错:

ORA-08177: 无法进行串行化访问

当一个串行化事务因为无法进行串行化访问(Cannot serialize access)错误而失败时,应用程序可以 选择以下几种处理方式:

1、将错误发生之前的操作提交

2、执行其他操作(执行前可以回滚到事务内的某个保存点)

3、撤销整个事务

下图显示了一个事务遇到无法进行串行化访问后, 程序进行回滚并尝试重新执行此事务的例子:

图中显示了一个串行化事务,其中首先执行了两个相同的 SELECT 语句,接着执行了一个 UPDATE 语句。即便在两个 SELECT 执行之间有其他事务修改了相关数据,这两个 SELECT 也能够返回相同的结果。当 UPDATE 语句更新数据时,所更新的数据在此事务开始后被其他事务修改并提交过,Oracle 将报错 Cannot Serialize Access。这个错误将导致事务回滚并尝试重新执行。

已提交读取隔离与串行化隔离的区别

Oracle 为应用程序开发者提供了两种特性相异的事务隔离级别。已提交读取隔离和串行化隔离都能实现高度的数据一致性及并发访问能力。这两种隔离级别都能够利用 Oracle 的读一致性多版本并发访问控制模型及独有的行级锁(row-level locking)技术,从而减少并发事务间的竞争。应用程序开发者可以使用这两种隔离级别开发符合现实要求的应用系统。

事务集数据一致性

我们可以参考以下场景来研究 Oracle 中的两种隔离级别:假设现有一组数据库表(或称为一组数据集),一系列读取表数据的查询,以及一组在任意时间提交的事务。如果一个数据库操作(一个查询或一个事务)中所有读取返回的数据是由同一组已提交事务写入的,我们就称此操作满足事务集数据一致性(transaction set consistent)。相反,当一个数据库操作内的不同读取反映了不同事务集对数据的修改,此操作就不满足事务集数据一致性。换句话说,一个不满足事务集数据一致性的操作所看到的数据库的状态是由不同的已提交事务集决定的。

在已提交读取隔离模式下,Oracle 能保证每个语句的事务集数据一致性。而在串行化隔离模式下,Oracle 能保证每个事务的事务集数据一致性。

下表总结了 Oracle 中已提交读取事务和串行化事务的关键区别。

已提交读取
 
串行化
 
脏写入(dirty write)
 
不可能
 
不可能
 
脏读取(dirty read)
 
不可能
 
不可能
 
不可重复读取(nonrepeatable read)
 
可能
 
不可能
 
不存在读取(phantom)
 
可能
 
不可能
 
与 ANSI/ISO SQL 92 标准兼容
 

 

 
唯一的数据视图的使用范围
 
语句
 
事务
 
事务集数据一致性
 
语句级
 
事务级
 
行级锁
 

 

 
读操作(reader)阻塞写操作(writer)
 

 

 
写操作阻塞读操作
 

 

 
针对不同数据行的写操作
是否相互阻塞
 

 

 
针对相同数据行的写操作
是否相互阻塞
 

 

 
等待导致阻塞的事务(blocking transaction)
 

 

 
会出现无法进行串行化访问(Cannot serialize access)错误
 

 

 
在导致阻塞的事务结束后
将发生错误
 

 

 
在导致阻塞的事务提交后
将发生错误
 

 

 

选择隔离级别

已提交读取隔离

对于大多数应用来说,已提交读取隔离是最适合的事务隔离级别。已提交读取隔离能够最大限度地保证数据并发性,但在某些事务中可能会出现不可重复读取或不存在读取,因此略微增加了出现数据不一致性的风险。

在对性能要求较高的系统中,为了应对较高的事务到来率(transaction arrival rate),系统需要提供更大的事务吞吐量和更快的响应速度,此时采用串行化隔离可能难以实现。还有一类系统,其事务到来率较低,出现不可重复读取或不存在读取的风险也较低。以上两种系统均适合采用已提交读取隔离 。

Oracle 的已提交读取隔离能够确保所有查询的事务集数据一致性。即查询获得的数据是处于一致性状态下的。因此在 Oracle 中已提交读取隔离能够满足大多数应用的要求。而在没有多版本并发访问控制的数据库管理系统中,开发者可能需要采用更高程度的隔离方式。

在已提交读取隔离模式下,开发者不需要在应用逻辑中捕获无法进行串行化访问错误,也无需回滚并重新执行事务。在大多数应用程序中,几乎不会有在一个事务中执行同一查询多次的情况,因此在这些应用程序中,为防止出现不可重复读取或不存在读取而采取的保护措施并不重要。 如果开发者选择已提交读取隔离,就能够省略在每个事务中加入错误检查及事务重做的代码。

Oracle 的串行化隔离适合于具备以下特点的系统:出现修改相同数据的事务的几率较小,且长时间执行的事务以只读操作为主。最适合采用串行化隔离的系统是大型数据库,且其中主要运行更新少量数据的短小事务。

串行化隔离能够提供更好的数据一致性,她能阻止不可重复读取或不存在读取的现象。当一个读或写事务中需要运行同一查询多次时,串行化隔离的作用更加明显。

某些数据库管理系统在实现串行化隔离时,无论读写操作都要对整个数据块加锁。而 Oracle 则采用了无阻塞查询及低粒度的行级锁技术,减少了读写操作间的竞争。对于存在较多读写竞争的应用,Oracle 的串行化隔离与其他数据库管理系统相比能够大大地提高事务处理能力。因此,某些应用在 Oracle 中可以采用串行化隔离,而在其他数据库管理系统则未必可行。

运行在串行化隔离模式下的事务中的所有查询所获得的数据都来自同一时间点,因此这种隔离级别适合于需要执行多个满足一致性的查询的事务。例如,汇总数据并将结果写入数据库的报表应用可以采用串行化隔离,因为串行化事务所提供的数据一致性与READ ONLY事务相同,但其中还可以执行,和操作。


参考至:Oracle 10G R2 Concepts

本文原创,转载请注明出处、作者

如有错误,欢迎指正

邮箱:czmcj@163.com

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


文章浏览阅读773次,点赞6次,收藏9次。【代码】c# json字符串转Oracle的insert into的小程序。
文章浏览阅读8.7k次,点赞2次,收藏17次。此现象一般定位到远端的监听服务来找问题,在远端查看监听服务状态(具体看下面的解决方案会详细呈现),服务是否开启,另外查看监听端点概要是否存在host未指向到计算名的,如无直接进入监听配置文件listener.ora内添加指向即可。2、查看监听服务状态 lsnrctl status,右边为远端端点状态,未添加host指向到计算名;1、本地及远端安装好Oracle并配置好连接,Oracle服务和监听已启动;1、远程Oracle数据库:Oracle11g R2。或者进入下述服务手动重启。,再进行远程连接即可。_ora-12541:tns:无监听程序
文章浏览阅读2.8k次。mysql脚本转化为oracle脚本_mysql建表语句转oracle
文章浏览阅读2.2k次。cx_Oracle报错:cx_Oracle DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library_cx_oracle.databaseerror: dpi-1047: cannot locate a 64-bit oracle client libr
文章浏览阅读1.1k次,点赞38次,收藏35次。本文深入探讨了Oracle数据库的核心要素,包括体系结构、存储结构以及各类参数。通过解析Oracle数据库的体系结构,读者可以深入了解其内部组成和工作原理。存储结构部分介绍了数据在Oracle中的存储方式,从表空间到数据文件的层层逻辑。最后,我们深入探讨了Oracle数据库中各类参数的作用和配置方法,帮助读者更好地理解和优化数据库性能。本文旨在帮助读者全面理解Oracle数据库的运作机制,为其在实践中的应用提供基础和指导。
文章浏览阅读1.5k次。默认自动收集统计信息的时间为晚上10点(周一到周五,4个小时),早上6点(周六,周日,20个小时)由于平时默认每天只收集4小时,时间有点短了,改成每天可收集8小时。oracle 18c中默认是打开的。查看当前自动收集统计信息的时间。_oracle自动收集统计信息
文章浏览阅读929次,点赞18次,收藏20次。只有assm(Automatic Shared Memory Management)模式可以使用大页,需要关闭amm(Memory Manager Process)HugePages_Free: 306 (空闲306页,已使用306-306=0页)防止oracle使用的内存交换,所以设置的大小与oracle配置的sga、pga相关。HugePages_Rsvd: 0 (操作系统承诺给oracle预留的页数)HugePages_Total: 306 (总共306页)_oracle11g 大页
文章浏览阅读801次。例如:10046:0,1,4,8,12。默认redo日志有三个,大小为50M,循环覆盖使用。redo log再覆盖之前,会被归档,形成归档日志。答:不同事件,不同级别。trace的不同级别?_oracle 日志
文章浏览阅读4.2k次,点赞84次,收藏77次。主要讲解MySQL中SQL的DDL语句,其中包括对数据库和表的一系列操作。_sql ddl 新增字段 mysql
文章浏览阅读1.1k次。ON DEMAND:仅在该物化视图“需要”被刷新了,才进行刷新(REFRESH),即更新物化视图,以保证和基表数据的一致性;ON COMMIT:一旦基表有了COMMIT,即事务提交,则立刻刷新,立刻更新物化视图,使得数据和基表一致。Method =>'C',物化视图有三种刷新方式:COMPLETE、FAST和FORCE。物化视图会占用空间,一半可用于大量数据查询时,减缓主表的查询压力使用。例如创建一个物化视图,让对接单位查询。_oracle物化视图定时刷新
文章浏览阅读713次,点赞21次,收藏18次。1.背景介绍在当今的大数据时代,数据量越来越大,传统的关系型数据库已经无法满足业务需求。因此,NoSQL数据库技术迅速崛起,成为企业和开发者的首选。Oracle NoSQL Database是Oracle公司推出的一款分布式NoSQL数据库产品,具有高性能、高可用性和易于扩展等特点。在本文中,我们将深入了解Oracle NoSQL Database的集成与开发者工具,帮助您更好地掌握这款产品的...
文章浏览阅读2.5k次,点赞2次,收藏4次。今天遇见一个问题需要将字段中包含中文字符串的筛选出来。_oracle查询包含中文字符
文章浏览阅读802次。arcmap 在oracle删除表重新创建提示表名存在解决放啊
文章浏览阅读4.3k次,点赞2次,收藏4次。Oracle连接数据库提示 ORA-12638:身份证明检索失败_ora-12638
文章浏览阅读3.4k次,点赞6次,收藏25次。etc/profile是一个全局配置文件,所有用户登录都会使用该文件构建用户环境。与windows配置环境变量是一个道理。选择Linux系统,找到适合自己系统的安装包,我的是CentOS 8 x64。接下来需要登陆Oracle账户才能下载,无账户的可以自己注册一个。Linux中export 命令用于设置或显示环境变量。模式,利用上下键到文档最后,添加以下代码。出现如图所示版本号字样,则说明安装成功。点击下载,勾选1,点击2。记住完整路径用于后面配置。找到Java并点击进去。往下翻,找到Java8。_linux安装jdk1.8
文章浏览阅读2.4w次,点赞26次,收藏109次。JDK 是的简称,也就是 Java 开发工具包。JDK 是整个 Java 的核心,其中JDK包含了 Java 运行环境(Java Runtime Envirnment,简称 JRE),Java 工具(比如 javac、java、javap 等等),以及 Java 基础类库(比如 rt.jar)。最主流的 JDK 是Oracle公司发布的 JDK,除了 Oracle JDK(商业化,更稳定)之外,还有很多公司和组织开发了属于自己的 JDK,比较有名的有IBM JDK(更适合 IBM) 和OpenJDK。_jdk安装教程
文章浏览阅读7.5w次。出现 “java.sql.SQLNonTransientConnectionException:Could not create connection to database server” 的错误通常是由于无法连接到数据库服务器引起的。_java.sql.sqlnontransientconnectionexception: could not create connection to
文章浏览阅读849次,点赞7次,收藏10次。在ClickHouse中创建用户、数据库并进行权限分配是一个重要的管理任务,它涉及到安全性和访问控制。下面是一个基本的指南来帮助你完成这些操作:1. 创建数据库首先,需要创建一个数据库。使用以下命令:CREATE DATABASE IF NOT EXISTS your_database_name;将 your_database_name 替换为你想要的数据库名。2. 创建用户接下来,创建一个新用户。使用以下命令:CREATE USER your_username IDENTIFIED WIT_在clickhouse中如何创建用户 赋权
文章浏览阅读1.2k次,点赞53次,收藏39次。本文是一篇关于Oracle数据库安装和使用的博文摘要。作者以轻松幽默的笔调介绍了自己在实验中掌握的Oracle数据库基本操作,包括使用组件查看命令、配置数据库监听器等。作者也分享了在实验中遇到的一些有趣问题,如SQL语句缺少分号导致的意外错误。此外,作者还强调了登录sys用户和启动实例加载数据库的注意事项,并鼓励读者面对挑战时保持乐观,不断提升自己的能力。整体风格风趣严谨,引人入胜。
文章浏览阅读820次,点赞17次,收藏16次。KingbaseES、xml、dbms_xmlgen、SETSKIPROWS、人大金仓、KingbaseES兼容Oracle包dbms_xmlgen的功能是通过SQL查询将关系表中数据转化为XML文档。转化方式一共有两种:(1)通过查询字符串直接转化。(2)通过上下文句柄转化。对于通过查询字符串直接转化的方式,无法跳过若干行进行查询,只能直接将表格中的所有数据转化为XML文档。