0

我对 IBM DB2 for z/OS 的 CURSOR 中的 FOR UPDATE 子句有疑问。假设隔离级别光标稳定性(BIND 命令中的标准参数)。DB2 版本为 11。

我的第一个问题是:使用 FOR UPDATE 子句编码的 CURSOR 是否可以防止并发事务从读取 CURSOR 当前所在的行开始?我的第二个问题是:UPDATE ... WHERE CURRENT OF ... 语句是否检测到在打开 CURSOR 之后和从 CURSOR 结果集中获取更新行之前何时更改了更新行?

我在网上阅读了一些关于这些问题的相互矛盾的陈述。根据我(当前)的理解,FETCH 操作仅在获取的行上获取更新锁,因此并发事务至少可以读取同一行。U-Lock 仅在实际完成 UPDATE WHERE CURRENT OF CURSOR 的情况下才升级为 X-Lock(取决于应用程序逻辑)。但这让我感到困惑,因为它不会防止丢失更新现象(当允许并发进程在第一个进程中的更新完成之前读取值时,它会继续使用旧值进行处理并覆盖第一个进程的更新通过 CURRENT OF CURSOR 更新的进程)。

4

1 回答 1

1

使用该FOR UPDATE子句编码的游标能否防止并发事务读取游标当前所在的行?

否 - 在隔离级别 CS 的情况下,Db2 将在当前行上持有一个 U 锁,这与可能需要的 S 锁兼容(请参阅后面关于 CURRENTDATA 绑定参数的评论以及它对避免读者使用 S 锁的影响)。

UPDATE ... WHERE CURRENT OF语句是否检测到在打开游标之后和从 CURSORs 结果集中获取更新行之前何时更改了更新的行?

否 - 对于隔离级别 CS,Db2 在读取行之前不会获取锁。如果在OPEN CURSOR需要不同的隔离级别后要求数据保持不变。

但这让我感到困惑,因为它不会防止丢失更新现象(当允许并发进程在第一个进程中的更新完成之前读取值时,它会继续使用旧值进行处理并覆盖第一个进程的更新通过 CURRENT OF CURSOR 更新的进程)。

假设两个事务都在使用FOR UPDATE并且UPDATE ... WHERE CURRENT OF这种情况不会发生。每次读取都会尝试获取 U 锁。由于 U 锁彼此不兼容,因此第二次读取将等待第一个 U 锁被释放。(https://www.ibm.com/docs/en/db2-for-zos/12?topic=locks-lock-modes-compatibility


对于更复杂的情况,其中一个(或两个)事务未使用FOR UPDATE并且UPDATE ... WHERE CURRENT OF有可能发生丢失更新现象。

很久以前,Db2 引入了绑定参数 CURRENTDATA 来帮助控制这种行为。

  • CURRENTDATA(NO)(从 Db2 10 开始默认)- 尽可能避免锁定,但会增加获取非当前数据的风险
  • CURRENTDATA(YES) - 获取 S 锁以降低获取非当前数据的风险。重要的是要注意 CURRENTDATA(YES) 并不能完全消除非当前数据的风险。

Db2 手册 - 选择 CURRENTDATA 选项

Gareth 在这方面有一些很棒的文章,其中包含更多详细信息 - Db2 for z/OS Locking for Application Developers Part 8

为了完全防止丢失更新的风险,一个好的方法是添加谓词以确保更新仅针对预期数据发生。Gareth 在他关于锁定的博客的第 9 部分中为此提供了三个选项。一般的想法是拥有像更新时间戳这样的东西,当行的任何部分被更新时,它总是被更新。WHERE然后在语句的子句中包含一个谓词,UPDATE以确保仅当更新时间戳与最初读取该行时的时间戳相同时才会发生更新。Db2 9 中的ROW CHANGE TIMESTAMP特性使这种方法更容易。

于 2021-10-03T02:02:24.993 回答