DB2 for z/OS:CURSOR FOR UPDATE 锁定行为

Posted

技术标签:

【中文标题】DB2 for z/OS:CURSOR FOR UPDATE 锁定行为【英文标题】:DB2 for z/OS: CURSOR FOR UPDATE locking behavior 【发布时间】:2021-11-23 02:02:43 【问题描述】:

我有一个关于 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更新的进程)。

【问题讨论】:

【参考方案1】:

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

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

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

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

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

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


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

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

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

Db2 manual - Choosing CURRENTDATA Option

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

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

【讨论】:

完美答案-谢谢兄弟! :) 附: gareth 的网站是我在研究期间遇到的网站之一,但不确定我是否理解正确 - 所以我更愿意直接问它......感谢您的澄清:thumbsup:

以上是关于DB2 for z/OS:CURSOR FOR UPDATE 锁定行为的主要内容,如果未能解决你的问题,请参考以下文章

在 DB2 sql for z/os 中用 0 填充 smallint

在 DB2 for Z/OS 中创建表分区

如何在 DB2 for Z/OS 中返回系统日期或日期时间?

DB2 v8 for z/OS 中的交叉连接

对 DB2 for z/OS 的存储过程调用中不支持字符串文字

DB2 10 for Z/OS, SQL LIKE Column Value Plus Wildcard DB2 w/o loss stage 1