用于z/OS的DB2:CURSOR FOR UPDATE锁定行为

cnjp1d6j  于 2022-11-07  发布在  DB2
关注(0)|答案(1)|浏览(182)

我有一个关于IBM DB2 for z/OS的CURSORs中的FOR UPDATE子句的问题。假设隔离级别游标稳定性(BIND命令中的标准参数)。DB2版本是11。
我的第一个问题是:用FOR UPDATE子句编写的CURSOR是否可以防止并发事务阅读CURSOR当前所在的行?我的第二个问题是:UPDATE... WHERE CURRENT OF...语句是否检测到在打开CURSOR之后、从CURSOR的结果集读取之前更新的行何时发生了更改?
我在网上读到了一些关于这些问题的相互矛盾的说法。(当前)理解,FETCH操作只需要获取读取行上的更新锁,因此并发事务至少可以读取同一行。(取决于应用程序逻辑)。但这让我感到困惑,因为这样就不能防止更新丢失现象(如果允许并发进程在第一个进程中的更新完成之前读取值,则它将继续处理旧值并覆盖通过CURRENT OF CURSOR更新的第一个进程的更新)。

pvabu6sv

pvabu6sv1#

使用FOR UPDATE子句编码的游标是否可以防止并发事务阅读游标当前所在的行?
否-使用隔离级别CS时,Db2将在当前行上持有一个U锁,该锁与可能需要的S锁兼容(请参阅后面有关CURRENTDATA绑定参数及其对避免读取器的S锁的影响的注解)。
在打开游标之后,从CURSOR结果集读取更新行之前,UPDATE ... WHERE CURRENT OF语句是否检测更新行何时发生更改?
否-使用隔离级别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
为了完全防止丢失更新的风险,一个好的方法是添加 predicate 来确保只对预期的数据进行更新。Gareth在他关于锁定的博客Part 9中提供了三种选择。一般的想法是有一个类似更新时间戳的东西,当行的任何部分被更新时,它总是被更新。然后在UPDATE语句的WHERE子句中包含一个 predicate ,以确保仅当更新时间戳与最初读取行时的时间戳相同时才进行更新。Db2 9中的ROW CHANGE TIMESTAMP特性使这种方法更容易。

相关问题