当前已落实的语义

锁定超时和死锁可在具有行级别锁定的游标稳定性 (CS) 隔离级别下运行,特别是未设计为阻止这类问题的应用程序。 某些高吞吐量数据库应用程序无法容忍等待事务处理期间发出的锁定。 而且,某些应用程序无法容忍处理未落实的数据,但仍要求读事务不会被阻塞。

在当前已提交语义下,不会获取行级锁,只会向读者返回已提交数据。 读取器不会等待写入器释放行锁。 相反,读取器返回的数据基于当前已提交的数据版本,即写入操作开始前的数据版本。
注: 在某些情况下,当前承诺的语义可能会退回到 CS 行为。 例如,在使用无限日志时,当前已提交的阅读器识别已提交版本的记录所需的日志被存档,就会出现这种情况。

缺省情况下,对于新数据库,将打开“当前已落实”语义。 您不必进行应用程序更改就可利用新行为。 要覆盖缺省行为,请将 cur_commit 数据库配置参数设置为 DISABLED。 覆盖该行为可能很有用,例如,如果应用程序需要阻止写程序同步内部逻辑。 从 V9.5 或之前版本升级数据库期间,cur_commit 配置参数将设置为 DISABLED,以便保持前发行版的行为。 如果要将“当前已落实”行为用于游标稳定性扫描,那么必须在升级后将 cur_commit 配置参数设置为 ON

当前已落实的语义仅适用于不涉及目录表的只读扫描和用于评估或实施约束的内部扫描。 因为当前已落实的语义是在扫描级别决定的,因此写程序的存取方案可能包括当前已落实扫描。 例如,只读子查询的扫描可以涉及“当前已落实”语义。 有关只读游标的定义,请参阅 DECLARE CURSOR 语句。

由于“当前已落实”语义遵守隔离级别语义,因此在“当前已落实”语义下运行的应用程序将继续遵守隔离级别。

“当前已落实”语义要求增加日志空间供写入者使用。 附加的空间用于记录事务期间对数据行进行的第一次更新。 为了检索该行的当前已落实映像,此数据是必需的。 根据工作负载的不同,这将对使用的日志总空间量产生不显著的影响或重大影响。 当 cur_commit 数据库配置参数设置为 DISABLED 时,不需要附加日志空间。

在当前已落实的语义下运行的应用程序将始终忽略未落实的插入。 有关详细信息,请参阅忽略未提交的插入性能变量的选项。

限制

下列限制适用于当前已落实的语义:
  • 要用于数据更新或删除操作的部分中的目标表对象不使用当前已落实的语义。 必须对要修改的行进行锁定保护,以确保它们在满足作为更新操作的一部分的任何查询谓词之后并不会更改。
  • 已经对某行进行了修改但是未落实修改的事务会强制当前已落实的阅读器访问适当的日志记录,以确定该行的当前已落实版本。 尽管实际上可以读取不再存在于日志缓冲区中的日志记录,但是,当前已落实的语义不支持从日志归档中检索日志文件。 这只会影响配置为使用无限记录的数据库。
  • 下列扫描不使用当前已落实的语义:
    • 目录表扫描。 当前已落实的语义仅适用于不涉及到用来评估或强制实施约束的内部扫描的只读扫描。 目前,承诺不适用于目录表的内部扫描,但可以应用于目录表的外部扫描,前提是注册表变量 DB2COMPOPT 设置为 LOCKAVOID_EXT_CATSCANS
    • 用来强制施加引用完整性约束的扫描
    • 引用 LONG VARCHAR 或 LONG VARGRAPHIC 列的扫描
    • 范围集群表 (RCT) 扫描
    • 使用空间索引或扩展索引的扫描
  • 如果出现不确定事务(由于应用程序崩溃,或者事务或资源管理器意外停运),那么此不确定事务已锁定的任何行将一直处于锁定状态,直到解决此不确定事务为止。 在这段时间内,仅当此不确定事务在崩溃或停运之前使用了当前已落实的语义时,当前已落实的阅读器才能读取这些行的当前已落实版本。 否则,当前已落实的阅读器在读取这些行之前,将等待解决此不确定事务(并等待释放这些锁定)。
  • 在 Db2® pureScale® 环境中,当前已落实的语义适用于任何成员上的应用程序。 如果行阅读器尝试访问被远程成员上的应用程序更新或删除的行,那么本地成员将从远程成员检索当前已落实的行数据。 但是,存在下列限制:
    • 如果该远程成员已关闭或者正在执行成员崩溃恢复,那么当前已落实的语义不适用。 行阅读器将等待该远程成员完成成员崩溃恢复,并且释放锁定之后才读取该行。
    • 如果在尝试检索当前已落实的行数据时与远程成员的通信失败,那么当前已落实的语义不适用。 行阅读器将等待释放锁定之后才读取该行。
    • 对于正在更新或删除远程成员的行的事务,如果在行阅读器与其进行通信之前已落实或者已回滚,那么行阅读器将再次尝试读取该行。 如果另一个远程成员上的事务在此时将更新或删除该行,那么行阅读器将再次尝试从该成员检索当前已落实的行数据。 行阅读器可能会在多次尝试之后放弃,改为在等待释放锁定之后才读取行数据。

监视

可以通过 db2pd -tcbstats 选项按每个表来监视当前已落实的行数据的检索。 请参阅 CCLogReadsCCRemoteReqsCCLockWaitsCCRemRetryLckWsdb2pd - 监控和故障排除 Db2c 数据库命令中的值。

示例

示例 1:
请考虑以下通过使用当前已落实的语义避免死锁的方案。 在此方案中,两个应用程序更新两个不同的表(如步骤 1 中所示),但尚未落实。 然后,每个应用程序尝试使用只读游标从另一个应用程序更新的表中读取,如步骤 2 中所示。 这些应用程序正在 CS 隔离级别下运行。
步骤 应用程序 A 应用程序 B
1 update T1 set col1 =? 其中 col2 =? update T2 set col1 =? 其中 col2 =?
2 select col1, col3, col4 from T2 where col2 >= ? 从 T1 中选择 col1, col5,其中 col5 =? 和 col2 =?
3 commit commit
如果没有“当前已落实”语义,那么在“游标稳定性”隔离级别下运行的这些应用程序可能会引起死锁,从而导致其中一个应用程序失败。 每个应用程序必须读取另一个应用程序正更新的数据时,会发生这种情况。

在当前已落实的语义下,如果正在步骤 2 中运行查询的其中一个应用程序查询另一应用程序正在更新的数据,那么第一个应用程序不会等待该锁定被释放。 因此,不可能发生死锁。 反而第一个应用程序会找到并使用数据的先前落实版本。

示例 2:
请考虑以下方案,在 Db2® pureScale® 环境中,应用程序避免发生锁定等待情况。 成员 1 上的应用程序 A 已更新表 T1 中的数据,但是尚未落实更改;成员 1 上的应用程序 B (与应用程序 A 属于同一成员)或者成员 2 上的应用程序 B (与应用程序 B 属于不同成员)使用游标稳定性隔离级别来尝试读取该数据:
步骤 pureScale 成员 1 上的应用程序 A 任何 pureScale 成员上的应用程序 B
1 update T1 set col1 = 12where col2 = ‘Ava’  
2   select col1 from T1 where col2 = ‘Ava’
3 commit  

如果没有当前已落实的语义,那么应用程序 B 将一直等到应用程序 A 已落实其更新并且释放行锁定之后才读取数据。 如果存在当前已落实的语义,那么应用程序 B 将改为使用先前已落实的数据版本。