隔离级别

与应用程序进程相关联的隔离级别确定该进程所访问的数据被锁定或者与其他同时执行的进程相隔离的程度。 该隔离级别在工作单元运行期间生效。

因此,应用程序进程的隔离级别指定:
  • 应用程序读取或更新的行可供其他同时执行的应用程序进程使用的程度
  • 其他同时执行的应用程序进程的更新活动可以影响应用程序的程度

静态 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 可能会获取相当多的锁定,所以此数目可能会超出 locklistmaxlocks 数据库配置参数所指定的限制。 为了避免锁定升级,在有可能发生锁定升级的时候,优化器可能会选择获取单个表级别锁定用于索引扫描。 如果您不希望进行表级别锁定,那么请使用“读稳定性”隔离级别。

评估引用约束时,DB2 服务器有时会将用于外表扫描的隔离级别升级到 RR,而不考虑用户先前设置的隔离级别。 这将导致其他锁定一直被挂起到落实为止,从而增加发生死锁或锁定超时情况的可能性。 为了避免这些问题,请创建只包含外键列的索引以供引用完整性扫描使用。

读稳定性 (RS)

读稳定性隔离级别只锁定应用程序在工作单元运行期间检索的那些行。 RS 确保在 UOW 完成之前,在该 UOW 运行期间读取的任何合格行不会被其他应用程序进程更改,并确保由另一个应用程序进程对行进行的更改在该进程落实更改前无法被读取。 对于 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 不会阻止其他应用程序访问正被读取的行,除非该应用程序尝试更改或删除表。

在 UR 下,可能会出现访问未落实的数据、不可重复的读以及幻像读等情况。 如果对只读的表运行查询,或者只发出 SELECT 语句并且查看其他应用程序尚未落实的数据不会引起问题时,此隔离级别适用。

对于只读游标和可更新游标,UR 的工作方式有所不同。
  • 只读游标可访问其他事务未落实的大部分更改。
  • 在事务处理期间,正由其他事务创建或删除的表、视图和索引不可用。 其他事务进行的任何其他更改在落实或回滚前都可被读取。 在 UR 下,可更新游标的工作方式就像隔离级别为 CS 一样。
如果未落实的读应用程序使用了模糊游标,那么它可以在运行期间使用 CS 隔离级别。 如果 PREPBIND 命令的 BLOCKING 选项值为 UNAMBIG(缺省值),那么模糊游标可以升级为 CS。 要避免这种升级,请执行下列操作:
  • 将该应用程序中的游标修改为明确游标。 将 SELECT 语句更改为包括 FOR READ ONLY 子句。
  • 保留应用程序中的模糊游标,但对该程序进行预编译或者对其进行绑定并指定 BLOCKING ALL 和 STATICREADONLY YES 选项,以便允许该程序运行时将模糊游标视为只读游标。

ISOLATION LEVEL 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