PARTIII-Oracle事务管理-数据并发性和一致性

news/2024/9/23 14:20:10/文章来源:https://www.cnblogs.com/crispy-bro/p/18405956

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数据库防止了脏读。

读一致性和事务表 数据库使用块头中的信息,也称为感兴趣的事务列表(ITL),来确定在数据库开始修改块时,事务是否未提交。每个段块的块头都包含一个ITL。ITL中的条目描述了哪些事务锁定了行,以及块中的哪些行包含了已提交和未提交的更改。ITL指向撤消段中的事务表,该表提供了对数据库所做的更改的时间信息。从某种意义上说,块头包含了影响块中每一行的事务的最近历史。CREATE TABLE和ALTER TABLE语句中的INITRANS参数控制保留的事务历史量。

9.1.2. 锁机制

通常情况下,多用户数据库使用某种形式的数据锁定来解决与数据并发性、一致性和完整性相关的问题。锁定是防止访问相同资源的事务之间发生破坏性交互的机制。

9.1.3. ANSI/ISO 事务隔离级别

SQL标准,已被ANSI和ISO/IEC采纳,定义了四个事务隔离级别。这些级别对事务处理吞吐量的影响程度不同。这些隔离级别是根据必须在并发执行的事务之间防止的现象来定义的。可防止的现象包括:

■ 脏读
一个事务读取了另一个尚未提交的事务写入的数据。

■ 不可重复读(模糊读)
一个事务重新读取它之前读取过的数据,发现另一个已提交的事务已经修改或删除了这些数据。例如,用户查询一行数据,然后稍后再次查询同一行数据,却发现数据已经发生了变化。

■ 幻读
一个事务重新执行一个查询,返回满足搜索条件的一组行,并发现另一个已提交的事务已经插入了额外满足条件的行。
例如,一个事务查询员工数量。五分钟后它执行相同的查询,但现在数量增加了一个,因为另一个用户插入了一条新员工的记录。满足查询条件的数据比之前更多,但与模糊读不同,之前读取的数据没有变化。

SQL标准根据事务在特定隔离级别下允许经历的现象来定义四个隔离级别。表9-1显示了这些级别。

Oracle数据库提供了读已提交(默认)和可序列化隔离级别。此外,数据库还提供了只读模式。

9.2. Oracle数据库事务隔离级别的概述

表9-1总结了ANSI标准的事务隔离级别。该标准是根据每个隔离级别允许或防止的现象来定义的。Oracle数据库提供了以下事务隔离级别:
■ 读已提交隔离级别
■ 可序列化隔离级别
■ 只读隔离级别

9.2.1. 读已提交隔离级别

在默认的读已提交隔离级别下,事务执行的每个查询只能看到在查询开始之前已经提交的数据,而不是事务本身开始之前的数据。这种隔离级别适用于数据库环境中,其中很少有事务可能会发生冲突。

在读已提交事务中的查询避免了读取在查询进行过程中提交的数据。例如,如果一个查询正在扫描一个包含百万行的表,并且如果一个不同的事务提交了一个对第950,000行的更新,那么当查询读取到第950,000行时,它不会看到这个变化。然而,由于数据库不阻止其他事务修改查询读取的数据,其他事务可能会在查询执行之间修改数据。因此,运行相同查询两次的事务可能会经历不可重复读和幻读。

9.2.1.1. 在读已提交隔离级别下的读一致性

在读已提交隔离级别下,每个查询都提供了一致的结果集,保证了数据的一致性,而无需用户采取任何行动。像UPDATE语句中的WHERE子句所隐含的查询,也保证了结果集的一致性。然而,隐含查询中的每个语句不会看到DML语句本身所做的更改,而是看到更改之前的数据状态。如果SELECT列表包含一个PL/SQL函数,那么数据库会在PL/SQL函数代码内的SQL语句级别应用语句级别的读一致性,而不是在父级SQL级别。例如,一个函数可能访问一个表,该表的数据被另一个用户更改并提交。对于函数中每次执行的SELECT,都会建立一个新的读一致性快照。

9.2.1.2. 在读已提交事务中的冲突写入

在读已提交事务中,当事务尝试更改由未提交的并发事务更新的行时,会发生冲突写入,有时这种并发事务被称为阻塞事务。读已提交事务会等待阻塞事务结束并释放其行锁。选项如下:

■ 如果阻塞事务回滚,则等待中的事务继续更改之前被锁定的行,就好像其他事务从未存在过一样。

■ 如果阻塞事务提交并释放其锁,则等待中的事务继续对新更改的行进行预期的更新。

表9-2显示了事务1(可以是可序列化的或读已提交的)与读已提交事务2的交互。表9-2展示了一个经典的情况,称为丢失更新(见第9-12页的“锁的使用”)。即使事务1已经提交了,它所做的更新也不在表中。制定处理丢失更新的策略是应用开发的重要部分。

9.2.2. 可序列化隔离级别

在可序列化隔离级别下,事务只能看到在事务本身开始时(而不是查询开始时)已经提交的更改,以及事务本身所做的更改。可序列化事务在一个环境中操作,这个环境让它看起来好像没有其他用户在数据库中修改数据。

可序列化隔离适用于以下环境:
■ 拥有大型数据库和只更新几行的短事务
■ 在两个并发事务修改相同行的可能性相对较低的情况下
■ 在主要是只读的相对长时间运行的事务中

在可序列化隔离级别下,通常在语句级别获得的读一致性扩展到整个事务。事务读取的任何行在重新读取时都保证是相同的。任何查询在事务期间都保证返回相同的结果,因此其他事务所做的更改对查询是不可见的,不管它已经运行了多长时间。可序列化事务不会经历脏读、模糊读或幻读。

Oracle数据库只允许可序列化事务在其他事务在可序列化事务开始时已经提交了对行的更改的情况下修改行。当可序列化事务尝试更新或删除在可序列化事务开始后由不同事务提交的数据更改时,数据库会生成错误:
ORA-08177: 无法为这个事务序列化访问

当可序列化事务因ORA-08177错误而失败时,应用程序可以采取几种行动,包括:
■ 提交到那时执行的工作
■ 执行额外的(但不同的)语句,可能在回滚到事务早期建立的保存点之后
■ 回滚整个事务

表9-3显示了可序列化事务如何与其他事务交互。如果可序列化事务不尝试更改在可序列化事务开始后由另一个事务提交的行,那么就避免了序列化访问问题。

9.2.3. 只读隔离级别

只读隔离级别类似于可序列化隔离级别,但只读事务不允许在事务中修改数据,除非用户是SYS。因此,只读事务不会受到ORA-08177错误的影响。只读事务对于生成报告非常有用,在这些报告中,内容必须与事务开始时的时间保持一致。Oracle数据库通过按需从undo段重建数据来实现读取一致性。由于undo段是循环使用的,数据库可以覆盖undo数据。长时间运行的报告存在风险,即用于读取一致性的undo数据可能已经被不同的事务重用了,这会引发“快照太旧”错误。设置undo保留期,即数据库在覆盖旧undo数据之前尝试保留旧undo数据的最小时间量,可以恰当地避免这个问题。

9.3. Oracle数据库锁定机制的概述

锁是一种机制,它防止事务在访问共享数据时发生破坏性交互,这些交互可能会错误地更新数据或错误地改变底层数据结构。锁在维护数据库的并发性和一致性中起着至关重要的作用。

9.3.1. 锁定行为概述

数据库根据获取锁的操作类型,维护了几种不同类型的锁。一般来说,数据库使用两种类型的锁:排他锁(exclusive locks)和共享锁(share locks)。在一个资源(如一行或一个表)上只能获得一个排他锁,但在一个单一资源上可以获得多个共享锁。

锁影响读取者(readers)和写入者(writers)之间的交互。读取者是对资源的查询,而写入者是对资源进行修改的语句。以下是Oracle数据库对读取者和写入者的锁定行为的总结规则:

  • 一行只在被写入者修改时被锁定。当一个语句更新一行时,事务仅为此行获取锁。通过在行级别锁定表数据,数据库最小化了对相同数据的争用。在正常情况下,数据库不会将行锁升级到块或表级别。
  • 一行的写入者会阻塞同一行的并发写入者。
    如果一个事务正在修改一行,那么行锁会阻止不同的事务同时修改同一行。
  • 读取者从不阻塞写入者。
    由于读取一行不会锁定它,写入者可以修改这行。唯一的例外是SELECT ... FOR UPDATE语句,这是一种特殊类型的SELECT语句,它会锁定它正在读取的行。
  • 写入者从不阻塞读取者。
    当一行正在被写入者更改时,数据库使用undo数据为读取者提供行的一致视图。

注意:在待处理的分布式事务的非常特殊情况下,读取相同数据块的读者可能需要等待写入这些数据块的写作者。

9.3.2. 锁的使用

在单用户数据库中,锁是不必要的,因为只有一个用户在修改信息。然而,当多个用户访问和修改数据时,数据库必须提供一种方法来防止对相同数据的并发修改。锁实现了以下重要的数据库需求:
■ 一致性
会话正在查看或更改的数据在用户完成之前,不能被其他会话更改。

■ 完整性
数据和结构必须正确地反映对它们的所有更改顺序。

Oracle数据库通过其锁定机制在事务之间提供数据并发性、一致性和完整性。锁定是自动执行的,不需要用户操作。
可以通过对单行的并发更新来说明锁的需求。在以下示例中,一个简单的基于Web的应用程序向最终用户提供员工的电子邮件和电话号码。应用程序使用如下的UPDATE语句来修改数据:

UPDATE employees SET email = ?, phone_number = ? WHERE employee_id = ? AND email = ? AND phone_number = ?

在前面的UPDATE语句中,WHERE子句中的电子邮件和电话号码值是指定员工的原始、未修改的值。这次更新确保应用程序修改的行在应用程序最后一次读取并显示给用户之后没有被更改。通过这种方式,应用程序避免了丢失更新数据库问题,其中一个用户覆盖了另一个用户所做的更改,有效地丢失了第二个用户的更新(第9-7页的表9-2展示了丢失更新的一个例子)。表9-4显示了当两个会话几乎同时尝试修改员工表中的同一行时的事件顺序。

Oracle数据库在执行SQL语句时会自动获取必要的锁。例如,在数据库允许会话修改数据之前,会话必须首先锁定数据。锁赋予会话对数据的独占控制权,这样在锁被释放之前,没有其他事务可以修改被锁定的数据。
由于Oracle数据库的锁定机制与事务控制紧密相关,应用程序设计者只需要正确定义事务,Oracle数据库会自动管理锁定。用户永远不需要显式锁定任何资源,尽管Oracle数据库也允许用户手动锁定数据。
以下部分解释了理解Oracle数据库如何实现数据并发性的重要概念。

9.3.3. 锁模式

Oracle数据库自动使用最低适用的限制级别,以提供最大程度的数据并发性,同时确保数据完整性。限制级别越低,数据对其他用户的可用性就越高。相反,限制级别越高,其他事务在获取锁的类型上就越受限制。Oracle数据库在多用户数据库中使用两种锁定模式:

■ 独占锁模式
这种模式防止关联资源被共享。当事务修改数据时,它会获取一个独占锁。首先锁定资源的事务是唯一可以在独占锁被释放之前更改资源的事务。

■ 共享锁模式
这种模式允许根据涉及的操作共享关联资源。多个用户读取数据时可以共享数据,持有共享锁以防止需要独占锁的写入者同时访问。多个事务可以在同一资源上获取共享锁。

假设一个事务使用SELECT ... FOR UPDATE语句选择单个表行。该事务获取一个独占行锁和一个行共享表锁。行锁允许其他会话修改除了锁定行之外的任何行,而表锁防止会话更改表的结构。因此,数据库允许尽可能多的语句执行。

9.3.4. 锁转换和升级

Oracle数据库在必要时执行锁转换。在锁转换中,数据库自动将较低限制性的表锁转换为较高限制性的锁。例如,假设一个事务对员工发出了SELECT ... FOR UPDATE,然后更新了锁定的行。在这种情况下,数据库会自动将行共享表锁转换为行独占表锁。事务对事务内插入、更新或删除的所有行持有独占行锁。由于行锁是在最高限制性级别上获取的,因此不需要或执行锁转换。锁转换与锁升级不同,锁升级发生在持有一个粒度级别的多个锁(例如,行)时,数据库将锁提升到更高粒度级别(例如,表)。如果用户锁定了表中的许多行,那么一些数据库会自动将行锁升级为单个表锁。锁的数量减少了,但锁定的内容的限制性增加了。Oracle数据库从不升级锁。锁升级大大增加了死锁的可能性。假设一个系统试图代表事务1进行锁升级,但由于事务2持有的锁而无法进行。如果事务2在继续之前也需要对相同数据进行锁升级,就会创建一个死锁。

9.3.5. 锁持续时间

Oracle数据库在某些事件发生时会自动释放锁,以便事务不再需要该资源。大多数情况下,数据库会在事务期间持有语句获取的锁。这些锁防止了脏读、丢失更新和破坏性DDL等并发事务中的破坏性干扰。

注意:由于未索引的外键而在子表上获得的表锁是在语句期间持有的,而不是事务期间。此外,如第9-27页的“用户定义锁概述”中所解释的,DBMS_LOCK包使得用户定义的锁可以随意释放和分配,甚至可以跨越事务边界。

Oracle数据库在提交或回滚时释放事务内语句获取的所有锁。当回滚到保存点时,Oracle数据库还会释放在保存点之后获取的锁。然而,只有不等待先前锁定资源的事务才能获取对现在可用资源的锁定。等待事务继续等待,直到原始事务完全提交或回滚(有关示例,请参阅第10-9页的表10-2)。

9.3.6. 锁和死锁

死锁是两个或多个用户等待由彼此锁定的数据的情况。死锁会阻止某些事务继续工作。Oracle数据库自动检测死锁,并通过回滚涉及死锁的一条语句来解决死锁,释放一组冲突的行锁。数据库向进行语句级回滚的事务返回相应的消息。回滚的语句属于检测到死锁的事务。通常,发出信号的事务应该显式回滚,但它可以在等待后重试回滚语句。

表9-5说明了两个事务处于死锁状态的情况。

死锁最常发生在事务显式覆盖Oracle数据库默认锁定的情况。由于Oracle数据库不升级锁且不对查询使用读锁,而是使用行级(而不是页级)锁定,因此死锁发生的情况较少。

9.4. 自动锁定概述

Oracle数据库会自动代表事务锁定资源,以防止其他事务执行需要对同一资源进行独占访问的操作。数据库根据资源和正在执行的操作自动获取不同级别限制的不同类型的锁。

注意:在执行简单读取时,数据库从不锁定行。Oracle数据库的锁分为以下几类:

9.4.1. DML锁

DML锁,也称为数据锁,保证了多个用户并发访问的数据的完整性。例如,DML锁防止两位顾客从在线书店购买最后一本可用的书。DML锁防止了同时进行的相互冲突的DML或DDL操作的破坏性干扰。

DML语句会自动获取以下类型的锁:

■ 行锁 (TX)
■ 表锁 (TM)

在后续部分中,每种锁类型或锁模式后的括号中的缩写是Oracle企业管理器(Enterprise Manager)中锁监视器使用的缩写。企业管理器可能会显示TM代表任何表锁,而不是指示表锁的模式(如RS或SRX)。

9.4.1.1. 行锁(TX)

行锁,也称为TX锁,是对表中的单行数据进行锁定。事务在通过INSERT、UPDATE、DELETE、MERGE或SELECT ... FOR UPDATE语句修改每行数据时,会获取该行的行锁。行锁一直存在,直到事务提交或回滚。

行锁主要作为排队机制,以防止两个事务同时修改同一行。数据库总是以排他模式锁定被修改的行,这样其他事务在持有锁的事务提交或回滚之前无法修改该行。行锁提供了最细粒度的锁定,因此提供了最佳的并发性和吞吐量。

注意:如果事务因为数据库实例故障而终止,那么块级恢复会在整个事务完全恢复之前使行数据可用。

如果一个事务获取了某行的锁,那么该事务也会获取包含该行的表的锁。表锁防止了会覆盖当前事务中数据更改的冲突性DDL操作。图9-2展示了对表中第三行的更新。Oracle数据库会自动在更新的行上放置一个排他锁,在表上放置一个次排他锁。

行锁与并发性 表9-6展示了Oracle数据库如何使用行锁来实现并发。三个会话同时查询相同的行。会话1和会话2继续对不同的行进行未提交的更新,而会话3不进行更新。每个会话都可以看到自己的未提交更新,但看不到其他任何会话的未提交更新。

行锁的存储与某些使用锁管理器在内存中维护锁列表的数据库不同,Oracle数据库将锁信息存储在包含被锁定行的数据块中。数据库使用排队机制来获取行锁。如果一个事务需要对一个未锁定的行加锁,那么这个事务就会在数据块中放置一个锁。这个事务修改的每一行都会指向存储在块头中的事务ID副本(参见第12-6页的“数据块概述”)。当一个事务结束时,事务ID仍然保留在块头中。如果不同的事务想要修改一行,它会使用事务ID来确定锁是否处于活动状态。如果锁处于活动状态,那么会话会请求在锁被释放时得到通知。否则,事务就会获取该锁。

9.4.1.2. 表锁(TM)

表锁,也称为TM锁,当一个事务通过INSERT、UPDATE、DELETE、MERGE、带有FOR UPDATE子句的SELECT或LOCK TABLE语句修改表时,会获取表锁。DML操作需要表锁来代表事务保留对表的DML访问权限,并防止与事务冲突的DDL操作。

表锁可以以下任何一种模式持有:
■ 行共享 (RS)
这种锁,也称为子共享表锁 (SS),表明持有表锁的事务锁定了表中的行并打算更新它们。行共享锁是表锁中限制性最小的模式,为表提供了最高程度的并发性。
■ 行独占表锁 (RX)
这种锁,也称为子独占表锁 (SX),通常表明持有锁的事务已更新表行或发出了SELECT ... FOR UPDATE。SX锁允许其他事务在同一表中并发查询、插入、更新、删除或锁定行。因此,SX锁允许多个事务同时获得同一表的SX和子共享表锁。
■ 共享表锁 (S)
持有共享表锁的事务允许其他事务查询表(不使用SELECT ... FOR UPDATE),但只有在单个事务持有共享表锁时才允许更新。由于多个事务可能同时持有共享表锁,持有这种锁并不足以确保事务可以修改表。
■ 共享行独占表锁 (SRX)
这种锁,也称为共享子独占表锁 (SSX),比共享表锁更具限制性。一次只能有一个事务获得给定表的SSX锁。持有SSX锁的事务允许其他事务查询表(除了SELECT ... FOR UPDATE),但不允许更新表。
■ 独占表锁 (X)
这种锁是最限制性的,禁止其他事务执行任何类型的DML语句或在表上放置任何类型的锁。

9.4.1.3. 锁与外键

Oracle数据库最大化了父键与依赖外键之间的并发控制。在堆组织表中,锁定行为取决于外键列的索引。如果外键没有被索引,那么子表可能会更频繁地被锁定,死锁会发生,并且并发性会降低。因此,除非匹配的唯一键或主键从不更新或删除,否则Oracle推荐在大多数情况下对外键进行索引。

注意:对于非堆数据结构,如索引组织表和表簇,还适用其他考虑因素。

锁和未索引的外键
当以下两个条件都为真时,数据库会获取子表的全表锁:
■ 子表的外键列上不存在索引。
■ 一个会话修改了父表中的主键(例如,删除一行或修改主键属性)或将行合并到父表中。向父表插入数据不会获取子表的表锁。
假设hr.departments表是hr.employees的父表,其中包含未索引的外键department_id。图9-3显示了一个会话正在修改departments表中部门60的主键属性。

在图9-3中,数据库在修改部门60的主键期间获取了对employees表的全表锁。这个锁允许其他会话查询但不允许更新employees表。例如,不能更新员工的电话号码。在departments表上完成主键修改后,对employees的表锁会立即释放。如果departments表中有多个行的主键被修改,那么对employees的表锁会在departments中每个被修改的行上获取并释放一次。

注意:对子表的DML操作不会获取父表的表锁。

锁和已索引的外键

当以下两个条件都为真时,数据库不会获取子表的全表锁:

■ 子表中的外键列已经被索引。
■ 一个会话修改了父表中的主键(例如,删除一行或修改主键属性)或将行合并到父表中。

父表上的锁会阻止事务获取独占表锁,但不会阻止在主键修改期间对父表或子表进行DML操作。如果父表上发生主键修改的同时子表上也在进行更新,这种情况是更可取的。

图9-4显示了子表employees,其中department_id列已经被索引。一个事务从departments表中删除了部门280。这种删除不会导致数据库获取对employees表的全表锁,就像在“锁和未索引的外键”9-21页描述的场景那样。

如果子表指定了 ON DELETE CASCADE,则从父表中的删除操作可能导致从子表中的删除。例如,删除部门280可能导致删除employees表中该已删除部门的员工记录。在这种情况下,等待和锁定规则与您在从父表删除行之后再从子表删除行时相同。

9.4.2. DDL锁

数据字典(DDL)锁在进行中的DDL操作对对象进行操作或引用时保护模式对象的定义。只有在DDL操作期间被修改或引用的个别模式对象会被锁定。数据库从未锁定整个数据字典。

Oracle数据库代表任何需要它的DDL事务自动获取DDL锁。用户无法显式请求DDL锁。例如,如果用户创建了一个存储过程,那么Oracle数据库会自动获取存储过程定义中引用的所有模式对象的DDL锁。DDL锁防止这些对象在过程编译完成之前被更改或删除。

9.4.2.1. 独占式DDL锁

独占式DDL锁阻止其他会话获取DDL或DML锁。除了在第9-24页“共享DDL锁”中描述的之外,大多数DDL操作都需要独占式DDL锁来防止对可能修改或引用相同模式对象的其他DDL操作产生破坏性干扰。例如,不允许在ALTER TABLE添加列的同时DROP TABLE删除表,反之亦然。
独占式DDL锁持续到DDL语句执行和自动提交的期间。在获取独占式DDL锁期间,如果另一个操作持有模式对象的另一个DDL锁,则获取操作会等待直到较旧的DDL锁被释放,然后继续进行。

9.4.2.2. 共享DDL锁

共享DDL锁对于资源来说,可以防止与冲突的DDL操作发生破坏性干扰,但允许类似DDL操作的数据并发。例如,当执行CREATE PROCEDURE语句时,包含的事务会为所有引用的表获取共享DDL锁。其他事务可以并发地创建引用相同表的程序,并在相同表上获取并发的共享DDL锁,但没有任何事务可以在任何引用的表上获取独占式DDL锁。共享DDL锁持续到DDL语句执行和自动提交的期间。因此,持有共享DDL锁的事务可以保证在事务期间引用的模式对象定义保持不变。

9.4.2.3. 可中断解析锁

解析锁是由SQL语句或PL/SQL程序单元持有的,用于它引用的每个模式对象。解析锁的获取是为了在引用的对象被修改或删除时,可以使得关联的共享SQL区域失效。解析锁被称为可中断解析锁,因为它不阻止任何DDL操作,并且可以被中断以允许冲突的DDL操作。

解析锁在SQL语句执行的解析阶段在共享池中获取。只要该语句的共享SQL区域仍然在共享池中,锁就会被持有。

9.4.3. 系统锁

Oracle数据库使用各种类型的系统锁来保护内部数据库和内存结构。这些机制对用户是不可见的,因为用户无法控制它们的发生或持续时间。

9.4.3.1. 闩

闩是简单的低级序列化机制,用于协调多个用户对共享数据结构、对象和文件的访问。轻量级锁保护共享内存资源在被多个进程访问时不受破坏。具体来说,轻量级锁保护数据结构免受以下情况的影响:

  • 多个会话并发修改
  • 一个会话在读取时另一个会话在修改
  • 在被访问时内存的释放(老化)

通常,单个轻量级锁保护SGA中的多个对象。例如,DBWn和LGWR等后台进程从共享池分配内存以创建数据结构。为了分配这个内存,这些进程使用共享池轻量级锁来序列化访问,以防止两个进程同时尝试检查或修改共享池。分配内存后,其他进程可能需要访问如库缓存这样的共享池区域,这是解析所必需的。在这种情况下,进程只锁定库缓存,而不是整个共享池。与行锁等排队轻量级锁不同,轻量级锁不允许会话排队。当轻量级锁可用时,第一个请求轻量级锁的会话获得对其的独占访问权。轻量级锁自旋发生在进程在循环中反复请求轻量级锁时,而轻量级锁睡眠发生在进程在重新申请轻量级锁之前释放CPU。通常,Oracle进程在操纵或查看数据结构时会非常短暂地获取轻量级锁。例如,在处理单个员工的工资更新时,数据库可能会获取并释放数千个轻量级锁。轻量级锁的实现依赖于操作系统,特别是在进程等待轻量级锁的方式和时间上。轻量级锁的增加意味着并发性的减少。例如,过度的硬解析操作会为库缓存轻量级锁创建争用。V$LATCH视图包含了每个轻量级锁的详细使用统计信息,包括每个轻量级锁被请求和等待的次数。

9.4.3.2. 互斥锁

互斥对象(mutex)是一种低级机制,用于防止内存中的对象在并发进程访问时老化或被破坏。互斥锁类似于轻量级锁,但轻量级锁通常保护一组对象,而互斥锁保护单个对象。互斥锁提供了几个好处:

  • 互斥锁可以减少争用的可能性。因为轻量级锁保护多个对象,当进程尝试并发访问这些对象时,它可能成为瓶颈。通过序列化对单个对象而不是一组对象的访问,互斥锁增加了可用性。
  • 互斥锁比轻量级锁消耗更少的内存。
  • 在共享模式下,互斥锁允许多个会话并发引用。

9.4.3.3. 内部锁

内部锁是比轻量级锁和互斥锁更高级、更复杂的机制,用于多种目的。数据库使用以下类型的内部锁:

  • 字典缓存锁
    这些锁的持续时间非常短,它们在字典缓存条目被修改或使用时持有。它们确保正在解析的语句不会看到不一致的对象定义。字典缓存锁可以是共享的或独占的。共享锁在解析完成时释放,而独占锁在DDL操作完成时释放。

  • 文件和日志管理锁
    这些锁保护各种文件。例如,一个内部锁保护控制文件,以便一次只有一个进程可以更改它。另一个锁协调在线重做日志文件的使用和归档。数据文件被锁定,以确保多个实例以共享模式挂载数据库,或者一个实例以独占模式挂载它。因为文件和日志锁指示文件的状态,所以这些锁必然需要持有较长时间。

  • 表空间和回滚段锁
    这些锁保护表空间和回滚段。例如,所有访问数据库的实例必须就表空间是在线还是离线达成一致。回滚段被锁定,以便只有一个数据库实例可以写入一个段。

9.5. 手动数据锁定概述

Oracle数据库自动执行锁定,以确保数据并发性、数据完整性和语句级别的读取一致性。然而,您可以手动覆盖Oracle数据库默认的锁定机制。在以下情况下,覆盖默认锁定是有用的:

  • 应用程序需要事务级别的读取一致性或可重复读取。
    在这种情况下,查询必须在事务持续期间产生一致的数据,不反映其他事务的更改。您可以通过使用显式锁定、只读事务、可序列化事务或覆盖默认锁定来实现事务级别的读取一致性。

  • 应用程序要求事务对资源具有独占访问权,以便事务不必等待其他事务完成。
    您可以在会话或事务级别覆盖Oracle数据库的自动锁定。在会话级别,会话可以使用ALTER SESSION语句设置所需的事务隔离级别。在事务级别,包含以下SQL语句的事务会覆盖Oracle数据库默认的锁定:

    • SET TRANSACTION ISOLATION LEVEL语句
    • LOCK TABLE语句(锁定表或与视图一起使用时锁定基表)
    • SELECT ... FOR UPDATE语句

    上述语句获取的锁在事务结束或回滚到保存点时释放。

    如果Oracle数据库默认锁定在任何级别被覆盖,那么数据库管理员或应用程序开发人员应确保覆盖锁定程序正确运行。锁定程序必须满足以下标准:保证数据完整性,数据并发性是可接受的,死锁不可能发生或得到适当处理。

9.6. 用户定义锁概述

通过Oracle数据库锁管理服务,您可以为特定应用程序定义自己的锁。例如,您可能创建一个锁来序列化对文件系统上的消息日志的访问。因为保留用户锁与Oracle数据库锁相同,它具有包括死锁检测在内的所有Oracle数据库锁功能。用户锁永远不会与Oracle数据库锁冲突,因为它们带有前缀UL。

Oracle数据库锁管理服务通过DBMS_LOCK包中的程序提供。您可以在PL/SQL块中包含以下语句:

  • 请求特定类型的锁
    给锁一个在相同或另一个实例中的另一个程序中可识别的唯一名称。

  • 更改锁类型

  • 释放锁

这些服务允许您在数据库中实现更细粒度的控制,以满足应用程序特定的同步需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/802181.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker部署paddleocr过程中遇到的问题

坑1:尝试了下面csdn博客中的解决方案,但是不太行,后来发现是paddlepaddle-gpu的版本问题,版本改对后就OK了 https://blog.csdn.net/weixin_43021830/article/details/128243800 坑2:困扰了一周了,还是卡住了,目前尝试解决的两个思路 1、将paddleocr模块添加到python解释…

多语言文本 AI 情感分析 API 数据接口

多语言文本 AI 情感分析 API 数据接口 AI / 文本处理 AI 模型快速分析文本情感倾向 多语言文本 / 情感分析。1. 产品功能支持多语言文本情感分析; 基于特定 AI 模型,快速识别文本情感倾向; 适用于评论分析、舆情监控等场景; 全接口支持 HTTPS(TLS v1.0 / v1.1 / v1.2 / v1…

【unity开发】以OPPO手机为例,如何连接安卓设备并调试unity程序

1.有线调试 下面全程以oppo手机为例: 1.打开手机开发者模式 设置->关于手机->版本信息->狂点版本号直到弹出提示打开开发者模式即可2.打开USB调试 打开开发者模式之后 在设置->其他设置->开发者选项->USB调试打开即可3.USB数据线连接 使用USB数据线连接你的…

多语言文本 AI 纠错格式化 API 数据接口

多语言文本 AI 纠错格式化 API 数据接口 AI / 文本处理 AI 模型智能纠正 语法纠错 / 文本格式化。1. 产品功能支持多语言文本的语法纠错; 自动识别并纠正拼写错误、语法错误和标点符号使用不当; 优化文本格式,提高可读性; 基于AI模型,持续学习和更新,提高纠错准确率; 适…

从0到1搭建权限管理系统系列三 .net8 JWT创建Token并使用Av

说明 该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。 该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。 说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。 结合上一篇文章使用,味道更佳:…

9.23人工智能技术——绘图

主题:17.我变成了一棵树 设计思路:我选择的主题是一节语文课——我变成了一棵树的绘图设计。本节课的内容基调是童趣轻快活泼且富有想象气息的,所以我选择了明亮的蓝天白云绿草作为背景,使得画面温馨欢快。然后根据课文内容,我将课文里出现的一些关键事物添加到背景上,构…

kettle从入门到精通 第八十六课 ETL之kettle kettle调用https接口忽略SSL校验

1、在使用kettle调用接口的时候不可避免要调用http或者https接口,调用http接口kettle可以正常工作,但是遇到https接口的时候kettle就会提示证书有误,无法正常调用接口,今天咱们一起通过自研插件的方式来解决这个问题。自研插件需要有一定的java基础,git上有比较多的例子,…

串口环保212设备数据 转profinet IO项目案例

目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 测试数采仪的串口数据 2 4 配置网关采集212设备数据 4 5 用PROFINET IO协议转发数据 5 6 案例总结 8 1 案例说明数采仪通过串口输出环保212的数据,网关通过串口采集数采仪的数据。 网关把采集的数据转换成profinet IO从站数据。2 V…

从0到1搭建权限管理系统系列三 .net8 JWT创建Token并使用

说明该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。说明:OverallAuth2.0 是一个简单、易懂、功能强大的权限+可视化流程管理系统。 结合上一篇文章使用,味道更佳:从0…

任务四:制作二维码

使用草料二维码制作二维码https://cli.im/ 1.选择网址一栏,设置“网址跳转活码”,把网址填入后生成相应二维码 2.此网址为中少年快乐阅读平台http://202.96.31.36:8888/旨在拓展学生课外知识,扩大知识面 3.微信有时会当作不良网页,禁止跳转 把二维码加入海报中 1.成品

Leetcode 65. 有效数字

1.题目基本信息 1.1.题目描述 给定一个字符串 s ,返回 s 是否是一个 有效数字。 例如,下面的都是有效数字:”2″, “0089”, “-0.1”, “+3.14”, “4.”, “-.9”, “2e10”, “-90E3”, “3e+7”, “+6e-1”, “53.5e93”, “-123.456e789″,而接下来的不是:”abc”, “…

结对项目——实现一个自动生成小学四则运算题目的命令行程序

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/这个作业要求在哪里 结对项目 - 作业 - 计科22级34班 - 班级博客 - 博客园 (cnblogs.com)这个作业的目标 结对项目——实现一个自动生成小学四则运算题目的命令行程序成员1 陈奕奕 3222004552成员2 林闰…