隔离级别

当应用程序访问数据时, 隔离级别决定了该数据被锁定或与其他并发进程隔离的程度。 隔离级别在单位工作时间内有效。

因此,申请流程的隔离级别规定:
  • 应用程序读取或更新的行可供其他同时运行的应用程序进程使用的程度。
  • 其他同时运行的应用程序进程的更新活动对应用程序的影响程度。

静态 SQL 语句的隔离级别是作为程序包的属性指定的,并且将应用于使用该程序包的应用程序进程。 要指定隔离级别,请在程序准备过程中设置 ISOLATION 绑定或预编译选项。 对于动态 SQL 语句,默认隔离级别是在准备语句时为包指定的隔离级别。 请使用 SET CURRENT ISOLATION 语句对会话中发出的动态 SQL 语句指定另一隔离级别。 有关更多信息,请参阅 CURRENT ISOLATION 专用寄存器。 对于静态 SQL 语句和动态 SQL 语句而言,select-statement 中的 isolation-clause 都将覆盖专用寄存器(如果已设置的话)和绑定选项值。 有关更多信息,请参阅 Select-statement

隔离级别由锁定实施,所使用的锁定的类型将限制或阻止并发应用程序进程访问数据。 已声明临时表以及它们的行无法被锁定,这是因为它们仅可供声明它们的应用程序访问。

数据库管理器支持三种一般类别的锁定:
共享 (S)
挂起 S 锁定之后,并发应用程序进程只能对数据执行只读操作。
更新 (U)
在U锁下,如果并发应用程序未声明可能会更新某一行,则这些应用程序仅限于对数据进行只读操作。 数据库管理器假定当前正在查看行的进程可能会更新该行。
互斥 (X)
挂起 X 锁定之后,并发应用程序进程将无法以任何方式访问数据。 这种锁类型不适用于隔离级别为未承诺读取(UR)的应用程序,这种应用程序可以读取但不能修改数据。
无论采用哪种隔离级别,数据库管理器都将对插入、更新或删除的每一行挂起互斥锁定。 因此,所有隔离级别都能确保在工作单元期间,任何一行数据在应用程序处理过程中发生改变后,都不会被其他应用程序处理过程改变。 当工作单元完成后,数据库管理员将解除独占锁定。
注: 某些主机数据库服务器支持 无落实 (NC) 隔离级别。 对于其他数据库服务器而言,此隔离级别的行为与“未落实的读”隔离级别相同。
注: Db2® 产品的四个隔离级别中的任何一个都不允许 丢失更新 (LU) 并行问题。

以下按性能影响递减、数据访问或更新时所需维护递增的顺序,详细描述了各个隔离级别。

可重复的读 (RR)

可重复的读隔离级别将锁定应用程序在工作单元 (UOW) 运行期间引用的所有行。 如果应用程序在同一个工作单元中发出 SELECT 语句两次,那么每次将返回相同的结果。 在RR下,丢失更新、访问未提交的数据、不可重复读取和幻影读取是不可能的。

在 RR 隔离级别下,应用程序在 UOW 完成前可以任意次地检索和处理行。 但是,在该 UOW 完成之前,其他应用程序均无法更新、删除或插入将会影响结果集的行。 在 RR 隔离级别下运行的应用程序无法看到其他应用程序所作的未落实更改。 这种隔离级别可确保所有返回的数据在应用程序看到数据之前保持不变,即使使用了临时表或行阻止。

所引用的每一行都将被锁定,而不仅仅是锁定所检索的行。 例如,如果扫描 10000 行并对它们应用谓词,尽管可能只有 10 行满足条件,但仍会锁定全部的 10000 行。 如果再次运行查询,另一个应用程序无法插入或更新查询引用的行列表中的行。 RR的这一特性可防止误读。

由于 RR 可以获取大量锁,因此数量可能会超过 locklistmaxlocks 数据库配置参数指定的限制。 为了避免锁升级,如果锁升级的可能性较大,优化程序可能会选择为索引扫描获取单个表级锁。 如果您不希望进行表级别锁定,那么请使用“读稳定性”隔离级别。

Db2评估参照约束时,可能会偶尔将外部表扫描时使用的隔离级别升级到RR。 无论用户之前设置的隔离级别如何,升级都可能发生。 由于隔离级别升级,提交前可能会有更多锁被保持,这增加了死锁或锁超时的可能性。 为了避免这些问题,请创建只包含外键列的索引以供引用完整性扫描使用。

读稳定性 (RS)

读稳定性隔离级别只锁定应用程序在工作单元运行期间检索的那些行。 RS确保在UOW期间读取的任何合格行在UOW完成之前不会被其他应用程序进程更改。 RS还确保,在另一个应用程序进程提交更改之前,无法读取该进程对某行的任何更改。 在RS模式下,无法访问未提交的数据和不可重复的读取。 但是,有可能进行幻像读。 对行进行的并行更新还可能引入幻像读,在幻像读中,旧值不满足原始应用程序的搜索条件,但新更新值满足。

例如,以下情况可能出现幻像行:
  1. 应用程序进程 P1 读取满足某个搜索条件的行集 n。
  2. 然后应用程序进程 P2 插入满足该搜索条件的一行或多行并落实这些新插入操作。
  3. P1 再次读取具有相同搜索条件的行集,并获取原始行和 P2。

Db2 pureScale® 环境中,如果行在不同成员上同时更新,则在此隔离级别运行的应用程序可能会拒绝先前提交的行值。 要覆盖此行为,请指定 WAIT_FOR_OUTCOME 选项。

这种隔离级别可确保所有返回的数据在应用程序看到数据之前保持不变,即使使用了临时表或行阻止。

RS 隔离级别既提供了高度的并行性,也提供了稳定的数据视图。 所以,优化器确保在发生锁定升级前不获取表级别锁定。

RS 隔离级别适合于符合下列条件的应用程序:
  • 在并发环境中运行。
  • 要求合格行在一个工作单元内保持稳定。
  • 在一个工作单元内,不会重复发出相同的查询。
  • 当在一个工作单元内多次发出查询时,不需要相同的查询结果集。

游标稳定性 (CS)

游标稳定性隔离级别可在事务处理期间锁定游标所在的任何行。 此锁在取下下一排或交易结束前一直有效。 但是,如果更改了该行中的任何数据,那么在落实更改之前将一直挂起该锁定。

在此隔离级别下,其他应用程序无法在可更新游标定位于某一行上时更新或删除该行。 在 CS 下,无法访问其他应用程序未落实的数据。 然而,不可重复读取和幻影读取是可能的。

CS 是缺省隔离级别。 如果您希望最大程度地提高并行性,并且只需要查看已落实的数据时,此隔离级别适用。 在此隔离级别下运行的扫描将根据配置参数 cur_commit (当前承诺)进行。

Db2 pureScale 环境中,如果在另一个成员上同时更新该行,则在此隔离级别运行的应用程序可能会返回或拒绝先前提交的行值。 并行访问权解析设置的 WAIT FOR OUTCOME 选项可用于覆盖此行为。

注: 在 9.7中引入的 当前已落实 语义下,仅返回先前的已落实数据,但现在读者不会等待更新程序释放行锁定。 相反,读者返回的数据是基于当前提交版本的数据,即写入操作开始之前的版本。

未落实的读 (UR)

未落实的读隔离级别允许应用程序访问其他事务未落实的更改。 并且,UR 不会阻止其他应用程序访问正被读取的行,除非该应用程序尝试更改或删除表。

在统一资源管理器下,可以访问未提交的数据、不可重复读取和幻影读取。 如果以下任一情况属实,则适合使用此隔离级别:
  • 您对只读表进行查询。
  • 您只发出SELECT语句,查看其他应用程序提交的数据没有问题。
对于只读游标和可更新游标,UR 的工作方式有所不同。
  • 只读游标可访问其他事务未落实的大部分更改。
  • 在事务处理期间,正由其他事务创建或删除的表、视图和索引不可用。 其他事务进行的任何其他更改在落实或回滚前都可被读取。 在UR下运行的可更新游标,其隔离级别与CS相同。
如果未落实的读应用程序使用了模糊游标,那么它可以在运行期间使用 CS 隔离级别。 如果 PREPBIND 命令的 BLOCKING 选项值为 UNAMBIG(缺省值),那么模糊游标可以升级为 CS。 请采取以下措施防止升级:
  • 将该应用程序中的游标修改为明确游标。 将 SELECT 语句更改为包括 FOR READ ONLY 子句。
  • 将光标保留在应用程序中,使其保持模糊状态。 但是,请预先编译程序,或者将其与“阻止所有”和“静态读取”选项绑定,以便在程序运行时将模糊光标视为只读。

隔离级别 UR在列式表和行式表中的行为可能有所不同。

隔离级别的比较

表1 总结了所支持的隔离级别。
表 1. 隔离级别的比较
  UR CS RS RR
应用程序能否看到其他应用程序进程所做的未提交更改? False False False
应用程序更新能否修改其他应用程序进程所做的更改? False False False False
重新运行语句是否受其他应用程序进程的影响? 1 2
已更新的行是否能够被其他应用程序进程更新? 3 False False False False
已更新的行是否能够被其他在除 UR 以外的隔离级别下运行的应用程序进程读取? False False False False
已更新的行是否能够被其他在 UR 隔离级别下运行的应用程序进程读取?
已访问的行是否能够被其他应用程序进程更新? 4 False False
已访问的行是否能够被其他应用程序进程读取?
当前行是否能够被其他应用程序进程更新或删除? 5 见注释6 见注释6 False False
注:
  1. 以下场景是幻读现象的一个示例:工作单元 UW1 读取满足某些搜索条件的 n行数据集。 工作单元 UW2 插入一行或多行满足同一搜索条件的数据,然后执行落实。 然后,如果 UW1 在相同的搜索条件下重复读取,则会看到不同的结果集。 它显示最初读取的行以及 UW2的行。
  2. 如果基于标签的访问控制 (LBAC) 凭证在两次读操作之间发生更改,那么第二次读操作的结果可能会因为您访问不同的行而有所变化。
  3. 如果应用程序既读取表也写表,那么此隔离级别无法为该应用程序提供保护。 例如,应用程序在表格上打开光标,然后对同一表格进行插入、更新或删除操作。 使用打开的游标来访存更多的行时,该应用程序可能会看到不一致的数据。
  4. 以下场景是可读性不可重复现象的示例: UW1 读取一行。 工作单元 UW2 修改该行,然后执行落实。 那么,如果 UW1 再次读取该行,它可能会看到不同的值。
  5. 以下场景是脏读现象的一个示例:工作单元 UW1 修改了一行。 工作单元 UW2 在 UW1 执行落实前读取该行。 如果 UW1 回滚了更改, UW2 读取的数据就不存在了。
  6. 在 UR 或 CS 下,如果游标不可更新,那么当前行在某些情况下可以被其他应用程序进程更新或删除。 例如,如果执行缓存,那么可能会导致客户机上的当前行与服务器上的当前行不同。 此外,当当前承诺的语义在CS下使用时,正在读取的行可能存在未承诺的更新。 在这种情况下,始终将该行的当前已落实版本返回给应用程序。

隔离级别摘要

表 2 列出了与不同隔离级别相关联的并行问题。
表 2. 隔离级别摘要
隔离级别 访问未落实的数据 不可重复的读取 幻像读
可重复的读 (RR) 不可能 不可能 不可能
读稳定性 (RS) 不可能 不可能 可能
游标稳定性 (CS) 不可能 可能 可能
未落实的读 (UR) 可能 可能 可能
隔离级别不仅影响应用程序之间的隔离程度,还影响单个应用程序的性能特征。 性能会受到影响,因为获取和释放锁所需的处理和内存资源会随着隔离级别而变化。 发生死锁的可能性也随隔离级别的不同而有所变化。 表 3 提供了一个简单的启发式方法,可帮助您为应用程序选择初始隔离级别。
表 3. 选择隔离级别的准则
应用程序类型 要求数据高度稳定 不要求数据高度稳定
读/写事务 RS CS
只读事务 RR 或 RS UR