关于ORACLE的串行化隔离级别--来自ORACLE概念手册

为了描述同时执行的多个事务如何实现数据一致性,数据库研究人员定义了被

称为串行化处理(serializability)的事务隔离模型(transaction  isolation

model)。当所有事务都采取串行化的模式执行时,我们可以认为同一时间只有

一个事务在运行(串行的),而非并发的

以串行化模式对事务进行隔离的效果很好,但在此种模式下应用程序的效率将

大大降低。将并行执行的事务完全隔离意味着即便当前只存在一个对表进行查

询(query)的事务,其他事务 也不能再对此表进行插入(insert)操作了。(疑问:不是没有读取锁吗?)

总之,为了满足实际要求,我们需要在事务的隔离程度与应用的性能之间找出

一个平衡点。

关于这个疑问,我做了实验。证明这种说法是错误的,也可能是翻译的问题。

先执行第二个窗口,由于查询语句执行很长,此时去执行第一个窗口,发现是可以插入成功的,所以可以证明即使在串行化模式下,查询操作也不会阻塞插入操作。

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

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

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

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

在串行化隔离下,并发事务对数据库进行修改时只能顺序执行。具体来说,在

串行化隔离下,Oracle 在允许一个采用串行化隔离的事务修改某些数据行时,

需要判断在此事务开始执行之前,其他所有事务对这些数据行的修改已经被提交。

为了实现上述判断,Oracle 在数据块(data  block)内存储了相关的控制信息,

用于记录此块内数据行中所包含的数据是已提交或未提交的。即数据块内记录

了近期对本数据块内数据行进行了修改的所有事务及事务的状态。在一个数据

块内能够保留多少这样的记录是由 CREATE TABLE 或 ALTER TABLE 语句中的

INITRANS 参数设定的。

有些情况下,Oracle 无法获得足够的历史信息来判断某个数据行是否被一个事

务修改过。当大量事务在短时间内并发地修改同一数据块就会出现以上情况。

用户可以为可能被多个事务同时更新相同数据块的表设置较大的 INITRANS

值,以便避免上述情况。设置了较大的 INITRANS 值后,Oracle 就能为每个数

据块分配足够的空间来记录访问此数据块的事务的信息。

当一个串行化事务试图更新或删除数据,而这些数据在此事务开始后被其他事

务修改并进行了提交,Oracle 将报错:

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

当一个串行化事务因为无法进行串行化访问(Cannot serialize access)错误

而失败时,应用程序可以 选择以下几种处理方式:

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

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

?  撤销整个事务

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

Oracle 为应用程序开发者提供了两种特性相异的事务隔离级别。已提交读取

(read committed)隔离和串行化(serializable)隔离都能实现高度的数据

一致性及并发访问能力。这两种隔离级别都能够利用 Oracle 的读一致性多版

本并发访问控制模型及独有的行级锁(row-level locking)技术,从而减少并发事务间的竞争。应用程序开发者可以使用这两种隔离级别开发符合现实要求

的应用系统。

在已提交读取隔离模式(read committed)及串行化隔离模式(serializable)

下执行的事务都采用行级锁(row-level locking)技术,他们在更新被未提交

的并发事务修改的数据行时都会发生等待--等待未提交的并发事务提交或撤

销,并释放锁。如果未提交的并发事务进行了回滚,那么无论发生等待的事务

运行在何种隔离模式下,都能修改之前被锁住的数据行,如同未提交的并发事

务不存在一样。

当导致阻塞的事务(blocking transaction)[前文中提到的未提交的并发事务]

提交并释放了锁后,运行在已提交读写模式下的等待事务就能够继续执行其中

的更新操作。而运行在串行化模式下的等待事务将出现无法进行串行化访问

(Cannot serialize access)错误,因为阻塞事务在串行化等待事务开始后更

新了后者所存取的数据。

引用完整性:

无论在已提交读取隔离模式(read committed)还是串行化隔离模式

(serializable)中,Oracle 都不会使用读取锁,即某一个事务读取的数据可

能会被其他事务更新。在应用 级(application level)进行数据库一致性检

查的事务无法确定在其执行期间所读取的数据是否同时已被修改,因为所有修

改对此事务来说是透明的。如果应用程序的代码逻辑 需要进行应用级的一致性

检查,即便采用串行化事务(serializable transaction),也不能避免数据

不一致的问题。

对于存在大量并发用户快速地提交事务的系统来说,应用程序设计者应该从事

务处理量及响应时间的角度评估事务处理的性能。通常来说,为一个对性能要

求高的系统选择事务隔离级别时,需要在数据一致性及数据并发处理间进行平

衡。

在应用层对数据库一致性进行检查的应用逻辑必须注意,在两种隔离模式下读

操作都不会阻塞写操作。

已提交读取隔离:

对于大多数应用来说,已提交读取隔离(read committed)是最适合的事务隔

离级别。已提交读取隔离能够最大限度地保证数据并发性,但在某些事务中可

能会出现不可重复读取(non-repeatable read)或不存在读取(phantom),

因此略微增加了出现数据不一致性的风险。

在对性能要求较高的系统中, 为了应对较高的事务到来率 (transaction arrival

rate),系统需要提供更大的事务吞吐量和更快的响应速度,此时采用串行化

隔离可能难以实现。还有一类系统,其事务到来率较低,出现不可重复读取或

不存在读取的风险也较低。以上两种系统均适合采用已提交读取隔离

在已提交读取隔离模式下,开发者不需要在应用逻辑中捕获无法进行串行化访

问(Cannot serialize access)错误,也无需回滚并重新执行事务。在大多数

应用程序中,几乎不会有在一个事务中执行同一查询多次的情况,因此在这些

应用程序中,为防止出现不可重复读取或不存在读取而采取的保护措施并不重

要。 如果开发者选择已提交读取隔离,就能够省略在每个事务中加入错误检查

及事务重做的代码。

串行化隔离:

 

 

Oracle 的串行化隔离(serializable  isolation)适合于具备以下特点的系统:

出现修改相同数据的事务的几率较小,且长时间执行的事务以只读操作为主。

最适合采用串行化隔离的系统是大型数据库,且其中主要运行更新少量数据的

短小事务。

串行化隔离能够提供更好的数据一致性,她能阻止不可重复读取

(nonrepeatable read)或不存在读取(phantom)的现象。当一个读或写事务

中需要运行同一查询多次时,串行化隔离的作用更加明显。

某些数据库管理系统在实现串行化隔离时,无论读写操作都要对整个数据块加

锁。而 Oracle 则采用了无阻塞查询(nonblocking query)及低粒度的行级锁

技术(row-level locking),减少了读写操作间的竞争。对于存在较多读写竞

争的应用,Oracle 的串行化隔离与其他数据库管理系统相比能够大大地提高事

务处理能力。因此,某些应用在 Oracle 中可以采用串行化隔离,而在其他数

据库管理系统则未必可行。

运行在串行化隔离模式下的事务中的所有查询所获得的数据都来自同一时间点

(single point in time),因此这种隔离级别适合于需要执行多个满足一致

性的查询的事务。例如,汇总数据并将结果写入数据库的报表应用可以采用串

行化隔离,因为串行化事务所提供的数据一致性与 READ ONLY 事务相同,但其

中还可以执行 INSERT,UPDATE,和 DELETE 操作。

如果事务中存在使用了子查询的 DML 语句,应该使用串行化隔离来保证一致性

的读取。

在实现串行化隔离事务时,应用开发者必须编码来捕获无法进行串行化访问

(Cannot serialize access)错误,之后回滚并重做事务。在其他数据库管理

系统中需要类似的代码来处理死锁(deadlock)。有时为了遵从已有系统的标

准,或者当应用可能运行在多种数据库管理系统上时,应按照串行化隔离的要

求来设计事务处理代码。具备检查并处理串行化错误功能的事务也可以运行在

Oracle 的已提交读取(read committed)隔离模式下,因为此种隔离模式下不

会产生串行化错误。

如果系统中存在长时间运行的写事务,且其所操作的数据同时还会被大量的小

事务更新,则此类系统不应采用串行化模式。因为长事务所需更新的数据可能

会被其他事务抢先更新,则长事务可能需要重复地回滚,浪费系统资源。需要

注意的是,其他数据库管理系统所实现的串行化隔离(使用读取锁

(read-locking))同样不适合上述情况,因为长事务(即便是只执行读取操

作的事务)会和短小的写事务相互阻塞。

应用开发者在采用串行化隔离时应考虑回滚及重做事务所带来的开销。而在采

用读取锁的数据库管理系统中,死锁会频繁出现,在这样的系统中采用串行化

隔离,必须 令因死锁而终止的事务回滚并重做。如果一个系统对数据访问的竞

争较激烈,那么处理串行化错误将消耗大量资源。

在大多数系统中,一个事务发生无法进行串行化访问(Cannot serialize

access)错误后重做时再次与其他事务冲突的几率较小。基于上述原因,采用

串行化隔离时,容易与其他事务产生竞争的语句应该在事务开始后尽早执行。

但是我们始终无法保证事务能够成功执行,因此在应用程序中应该限制重做的

次数。

尽管 Oracle 的串行化隔离模式与 SQL92 兼容,而且与采用读取锁的实现方式

相比具备很多优点,但是 Oracle 串行化隔离所包含的语义与其他数据库管理

系统不完全相同。 应用开发者必须注意, 与其他数据库管理系统不同, 在 Oracle

中读操作不会阻塞写操作。在应用级(application level)对数据库一致性进

项检查的事务需要使用 SELECT FOR UPDATE 之类的技巧才能避免错误。当从其

他数据库管理系统向 Oracle 迁移应用时,尤其要注意上述问题。

综上所述,我理解ORACLE的串行化模式,就是两点:

事务级读一致性。

在事务开始的点开始,就会独占当前事务里所涉及的所有更新操作,拒绝其他事务来对独占的数据进行更新。如何保证这点呢,分两种:首先,事务在开始的时候回判断是否存在未提交的更新(可能会出现判断遗漏),如果没有才会继续,其次,举例,一个事务已经执行了一半,一种是当前事务已经执行的更新操作,由于没有提交,其他事务肯定只能等待,不能修改,另外一种是当前事务还没有执行的更新操作,在等到执行这段更新代码的时候,会去查看其他事务是否在当前事务开始后执行了提交(针对上面判断遗漏的情况),如果有,那么将抛出错误。

所在,这种方式实现了,事务的串行执行。串行执行并不是说,当前数据库中的所有事务都会串行排队,而只是针对事务中所涉及的更新数据,不会与其他事务并行修改。

时间: 2024-10-06 19:10:16

关于ORACLE的串行化隔离级别--来自ORACLE概念手册的相关文章

PostgreSQL串行化隔离级别(SSI)的能力与实现

https://zhuanlan.zhihu.com/p/37087894 PostgreSQL9.1是第一个采用Serializable Snapshot Isolation(SSI)实现串行化隔离级别的生产级数据库. 本文的目标是学习与分析SSI的设计思路,以及在PG中的实现与优化.首先介绍了隔离级别以及实现其的两个基本并发控制机制,给出了PG的SI未达到串行化的案例,分析原因并给出直观的解决思路,其次阐述了SSI的技术思路与关键环节,最后就PG内核中SSI的实现与优化思路进行了分析. 1.

可串行化隔离级别里的锁升级

在今天的文章里我会讨论下可串行化(SERIALIZABLE)隔离级别里会有的锁升级(Lock Escalations),还有你如何避免.在上个月的7月14日,我已经介绍了SQL Server里锁升级(Lock Escalations)的基本概念还有为什么需要它们.因此请你回到这个文章来理解下这个非常重要的概念. 可串行化(SERIALIZABLE)隔离级别 可串行化(SERIALIZABLE)隔离级别用来阻止所谓的幻影记录(Phantom Records).为了阻止它们,SQL Server使用

数据库管理(事务、ACID、并发、封锁、可串行化、隔离)(转)

1.数据库事务 1.1 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作. 1.2 事务的4个特性(ACID): (1)原子性(atomic)(atomicity)事务必须是原子工作单元:对于其数据修改,要么全都执行,要么全都不执行.通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的.原子性消除了系统处理操作子集的可能性. (2)一致性(consistent)(consistency)事务在完成时,必须使所有的数据都保持一致状态.事务结束

事务的隔离级别的演示:演示串行化

1.1.1 演示串行化l 开启两个窗口A,Bl 设置A窗口的隔离级别:serializableSET SESSION TRANSACTION ISOLATION LEVEL serializable;l 分别在两个窗口中开启事务:start transaction;l 在B窗口中插入一条记录insert into account values (null,'小李',10000);l 在A窗口中进行查询select * from account;*****发现A窗口已经卡住了(说明事务不允许出现并

数据库并发中的串行化

目前关系型数据库大多数情况都采用弱模型,由此引发的是并发时的隔离性混乱,通常解决方案是给数据库加乐观锁或悲观锁.只有少数个别的关系型数据库会给数据库事务加上串行化,但是需要注意是的是这样做虽然能够解决一些并发问题,但是相应的代价是并发时性能的降低以及少量死锁. 参考解道博文:http://www.jdon.com/47401

PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化)/约束类型/魔术方法小结

  前  言  OOP  学习了好久的PHP,今天来总结一下PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化). 1  PHP中的抽象类与抽象方法 1.什么是抽象方法?              没有方法体 {} 的方法,必须使用abstract 关键字修饰.这样的方,我们叫做抽象方法.                    abstract function say(); //    抽象方法 2.什么是抽象类?        

对象的序列化(串行化)分析(一)

对象的序列化(串行化)序列化概念:(1)对象的寿命通常随着生成该对象的程序的终止而终止.有时候,可能需要将对象的状态保存下 来,在需要时再将对象恢复.我们把对象的这种能记录自己的状态以便将来再生的能力.叫作对象的持续性(persistence).对象通过写出描述自己状 态的数值来记录自己 ,这个过程叫对象的串行化(Serialization-连续) .(2)一个对象随着创建而存在,随着程序结束而结束.那 如果我要保存一个对象的状态呢?Java序列化能够将对象的状态写入byte流存储起来,也从其他

.Net里的哈希表和串行化

.Net里的哈希表和串行化 介绍 本文介绍了,在.net里,使用哈希表和串行化的C#用法.这里使用的示例应用程序是一个电话簿.电话簿应用程序,是一个控制台的程序.它允许你添加,查看,列出和删除它里面的姓名和电话号码. 哈系表是"键-值"对的集合.在.net里,类Hashtable是哈希表的实现.通过调用Add方法,传递你想添加的键值对,可以完成添加.作为键来使用的这些对象,必须实现Object.Equals 和Object.GetHashCode方法. private Hashtabl

MFC 文件I/O和串行化

1.枚举所有文件夹(递归) void EnumerateFolders () { WIN32_FIND_DATA fd; HANDLE hFind = ::FindFirstFile (_T ("*.*"), &fd); if (hFind != INVALID_HANDLE_VALUE) { do { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { CString name = fd.cFileName; i