9.数据并发性和一致性
本章解释了Oracle数据库如何在多用户数据库环境中维护一致性的数据。
本章包含以下部分:
- 数据并发性和一致性的介绍
- Oracle数据库事务隔离级别的概述
- Oracle数据库锁定机制的概述
- 自动锁定的概述
- 手动数据锁定的概述
- 用户定义锁的概述
9.1. 数据并发性和一致性的介绍
在单用户数据库中,用户可以修改数据,而不必担心其他用户同时修改相同的数据。然而,在多用户数据库中,多个同时进行的事务中的语句可以更新相同的数据。同时执行的事务必须产生有意义且一致的结果。因此,多用户数据库必须提供以下内容:
- 数据并发性,确保用户可以同时访问数据
- 数据一致性,确保每个用户看到的数据视图是一致的,包括用户自己的事务所做的可见更改以及其他用户已提交事务的更改
为了描述事务在并发运行时的一致行为,数据库研究人员定义了一个称为可序列化的事务隔离模型。可序列化事务在一个环境中运行,使其看起来好像没有其他用户在修改数据库中的数据。
虽然通常期望事务之间有这种程度的隔离,但在可序列化模式下运行许多应用程序可能会严重损害应用程序的吞吐量。并发运行事务的完全隔离可能意味着一个事务不能向另一个事务正在查询的表中插入数据。简而言之,现实世界的考虑通常需要在完美的事务隔离和性能之间做出妥协。
Oracle数据库通过使用多版本一致性模型以及各种类型的锁和事务来维护数据一致性。通过这种方式,数据库可以向多个并发用户提供数据视图,每个视图都与时间点一致。因为可以同时存在数据块的不同版本,事务可以读取查询所需的时间点提交的数据版本,并返回与单个时间点一致的结果。
9.1.1. 多版本读一致性
在Oracle数据库中,多版本化是指能够同时实现数据的多个版本的能力。Oracle数据库维护多版本读取一致性,这意味着数据库查询具有以下特性:
-
读取一致性查询
查询返回的数据是已提交的,并且与单个时间点一致。
重要提示:Oracle数据库从不允许脏读,脏读发生在一个事务读取另一个事务中的未提交数据时。为了说明脏读的问题,假设一个事务在未提交的情况下更新了一个列值。第二个事务读取了更新后的脏(未提交)值。第一个会话回滚了事务,使得列值恢复为旧值,但第二个事务继续使用更新后的值,从而破坏了数据库。脏读会损害数据完整性,违反外键,并忽略唯一约束。
-
非阻塞查询
数据的读取者和写入者不会相互阻塞(见第9-12页的“锁定行为摘要”)。
9.1.1.1. 语句级读取一致性
Oracle数据库始终强制执行语句级读取一致性,这保证了单个查询返回的数据是已提交的,并且与单个时间点一致。单个SQL语句一致的时间点取决于事务隔离级别和查询的性质:
-
在已提交读隔离级别下,这个时间点是打开语句的时间。例如,如果一个SELECT语句在SCN 1000时打开,那么这个语句就与SCN 1000一致。
-
在可序列化或只读事务中,这个时间点是事务开始的时间。例如,如果一个事务在SCN 1000时开始,并且在该事务中发生了多个SELECT语句,那么每个语句都与SCN 1000一致。
-
在闪回查询操作(SELECT ... AS OF)中,SELECT语句明确指定了时间点。例如,您可以查询上周四下午2点时表的状态。
9.1.1.2. 事务级读取一致性
Oracle数据库还可以为事务中的所有查询提供读取一致性,这被称为事务级读取一致性。在这种情况下,事务中的每个语句都看到相同时间点的数据,即事务开始的时间。由可序列化事务执行的查询可以看到事务本身所做的更改。例如,一个更新员工信息然后查询员工信息的事务将看到这些更新。事务级读取一致性产生可重复的读取,并且不会使查询暴露于幻读。
9.1.1.3. 读取一致性和回滚段
为了管理多版本读取一致性模型,数据库必须在同时查询和更新表时创建一组读取一致的数据。Oracle数据库通过回滚数据来实现这一目标。每当用户修改数据时,Oracle数据库都会创建回滚条目,将其写入回滚段(第12-24页的“回滚段”)。回滚段包含由未提交或最近提交的事务更改的数据的旧值。因此,数据库中可以存在相同数据的多个版本,这些版本在不同的时间点上。数据库可以使用不同时间点的数据快照来提供数据的读取一致视图,并实现非阻塞查询。
在单实例和Oracle实时应用集群(Oracle RAC)环境中保证了读取一致性。Oracle RAC使用一种称为Cache Fusion的缓存到缓存块传输机制,将数据块的读取一致图像从一个数据库实例传输到另一个数据库实例。
读取一致性:示例图9-1展示了一个查询,该查询在已提交读隔离级别下使用回滚数据来提供语句级的读取一致性。
当数据库代表查询检索数据块时,数据库确保每个块中的数据反映了查询开始时块的内容。数据库根据需要回滚对块的更改,以将块重建到查询开始处理的时间点。
数据库使用一种称为SCN(系统更改编号)的机制来保证事务的顺序。当SELECT语句进入执行阶段时,数据库确定了查询开始执行时记录的SCN。在图9-1中,这个SCN是10023。查询仅看到与SCN 10023相关的已提交数据。
在图9-1中,SCN在10023之后的块表示已更改的数据,如两个SCN为10024的块所示。SELECT语句需要一个与已提交更改一致的块版本。数据库将当前数据块复制到新的缓冲区,并应用回滚数据来重建块的先前版本。这些重建的数据块称为一致读取(CR)克隆。
在图9-1中,数据库创建了两个CR克隆:一个块与SCN 10006一致,另一个块与SCN 10021一致。数据库返回查询的重建数据。通过这种方式,Oracle数据库防止了脏读。