IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management  >

DB2 Magazine:乐观锁定,第 2 部分

着眼于光明的一面——在涉及 DB2 for z/OS 锁定时,悲观方法通常并不合适

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


Bonnie Baker (bkbaker@bonniebaker.com), 顾问兼企业培训师

2008 年 1 月 18 日

在上一期的专栏文章中,我解释了 DB2 for z/OS 中乐观锁定的概念。我介绍了乐观锁定技术如何用于应用程序编程之中,降低锁定开销(包括潜在的超时)同时提升性能。我介绍了 SQL 函数(例如用于更新游标位置的函数)和 BIND 参数(例如 ISOLATION RR/RS、FOR UPDATE OF 或 CURRENTDATA(YES))都是非常悲观的,很可能会不必要地消耗过多 DB2 资源。

您或许会回忆起,我提到过,在 DB2 还处于 V1R1 的萌芽阶段时,乐观锁定技术就已经出现;但至今为止,这种技术一直由开发人员使用应用程序编程逻辑和特殊的 WHERE 子句谓词强制实施。最后,我还解释了,与盲目依赖 CURRENTDATA(YES) 等悲观技术并假设 DB2 总是保持必要锁定的程序相比,使用乐观技术的程序遭受数据完整性泄漏的可能性更低。

既然已经了解了乐观锁定的概念——无论是使用重新应用合格谓词的丰富 WHERE 子句实现还是使用 UPDATE TIMESTAMP 或更新计数器技术实现,因而可以继续讨论更加复杂的场景。在这一期的专栏中,我将讨论四个相关的主题:V4 中的行级锁定、V7 中的静态滚动游标及其“内置”乐观锁定、V8 中的动态滚动游标和行定位游标,以及 DB2 V9 中称之为“内置时间戳”的新数据类型。

行级锁定

为何要在这期专栏中讨论行级锁定?许多使用悲观锁定技术的用户都会遇到难以忍受的超时和死锁。为了解决这些问题,他们要尝试运用乐观锁定技术来获得更少的锁定,或将问题归咎于页面级锁定并切换到行级锁定,从而尝试解决超时问题。但采用此类方法时,其悲观主义更加细化。此时在行级而非页面获取锁。在最糟的情况下,如果有人使用 FOR UPDATE OF 读取一个页面上的六行,他将获得六个 U 锁,而不是一个。此外,由于行更新了 WHERE CURRENT OF CURSOR,此用户还要访问六次锁定管理器(而不是一次),才能将锁从 U 升级到 X。

总是可以通过更加简单的方法解决锁定问题。有时,创建索引来实现触及较少页面的更佳访问路径能解决锁定问题。如果使用出色的索引、匹配和映射谓词过滤掉不需要的行,要读取的页面数就会减少。如果不需读取一个页面,也就不必请求该页面上的锁。因而也不会获知无法读取该页面,原因是其他人持有该页面的不兼容锁。但不必创建更多索引。往往从悲观锁定技术切换到乐观锁定技术即可解决遇到的一切锁定问题。





回页首


V7 的静态滚动游标

在读取操作和随后的更新操作之间,有多种保护数据的方法(当然是乐观方法)。其中一种就是将游标声明为静态滚动游标。但并非任何静态滚动游标都可行。此游标必须是 SENSITIVE 静态滚动游标 —— 对其他用户和自己的程序所做出的更改敏感。借助这些游标,DB2 开发人员为我们提供了内置乐观锁定。使用 OPEN CURSOR 时,会具体化所有合格行的结果集。切记,我们告诉 DB2,游标对于我们自己(DECLARE SENSTIVE)和其他用户(FETCH SENSITIVE)对基表的更新或删除操作敏感。DB2 将确保结果集与实际表同步。为了保持同步,静态 CURSOR 的每次 FETCH 操作都会导致对实际表的同步读取操作,查看是否有其他用户更改或删除了基本行。我们会获得行的最新镜像(COMMIT 操作之后的),无论结果集中的内容是什么。如果查看数据,决定执行 UPDATE WHERE CURRENT OF CURSOR 或 DELETE WHERE CURRENT OF CURSOR,DB2 就必须读取基表,完成更改。由于基表必须被读取,DB2 可同步、自动地检查在获取同步镜像和决定更新行之间行中是否有任何值发生了变化。如果有值发生了变化,DB2 会发出通知。DB2 实际上是使用功能丰富的 WHERE 子句技术,如本文的第 1 部分所述(参见 DB2mag.com)。

此外,不必自行编写 WHERE 子句的代码。DB2 可以代为完成。如果行未发生任何更改,更新操作将得到执行,此次变更成为结果集的永久更改。如果行由其他用户更改过,UPDATE 操作不会成功完成,并且会向程序返回一条消息。

这种技术的另一优势在于,我们首次可以在有 ORDER BY 子句的游标上使用UPDATE/DELETE WHERE CURRENT OF CURSOR 技术。在静态滚动游标出现之前,如果 CURSOR 中包含排序语法(例如,ORDER BY),就无法使用 FOR UPDATE OF 和 UPDATE WHERE CURRENT OF CURSOR。在 CURSOR 声明中编写 ORDER BY 子句和 FOR UPDATE OF 子句会给此游标造成束缚,使之成为“纯只读游标”。

那么,我们仍然无法在同一游标声明内使用 ORDER BY 和 FOR UPDATE OF,但可以在CURSOR 声明内使用 ORDER BY,并在 FETCH 之后接 UPDATE WHERE CURRENT OF CURSOR。可以放心地采用这种方法——只要 CURSOR 是带有内置乐观锁定的 SENSITIVE STATIC SCROLL CURSOR 类型即可。





回页首


V8 中的动态滚动游标、行定位游标和锁定

在 V8 中,我们可以使用 DECLARE DYNAMIC SCROLL CURSOR。按照定义,这些游标总是从基表中读取行——而不是排序后的文件,也不是结果集。如果游标包含 ORDER BY,,那么就必须有索引可供 DB2 使用,以避免数据排序。此外,BIND 将失败。换言之,我们知道,无论是否使用排序语法,DB2 总是要读取基表。

因此,对于这些游标,即便有排序语法,也可以使用 UPDATE WHERE CURRENT OF CURSOR。如果有 ORDER BY,无法使用 FOR UPDATE OF,但仍可进行更新。

问题在于,与静态滚动游标不同,不存在内置的乐观锁定。我们要如何保证不存在数据完整性泄漏问题?所提到的乐观锁定技术并不可用。

如果使用允许利用一次与 DB2 的连接 FETCH 一行以上(比如一百行)的“行定位”新选项,问题会进一步恶化。如果随后使用 UPDATE WHERE CURRENT OF CURSOR,这 100 行将被更新,而我们无法检查 100 个时间戳。也不具备应用 100 条富 WHERE 子句进行比较的能力。

我已经提出了几种可行方法,但没有一种是我真正喜爱的。首先,切记我们在访问基表,也就意味着,使用 CURRENTDATA(YES) 进行 BIND 将导致 DB2 在 FETCH 和 UPDATE WHERE CURRENT OF CURSOR 之间保持一行或多行上的锁。

对于这种方法,我特别不喜欢的一点就是:CURRENTDATA 是一个 BIND 参数,应用于程序中的所有只读 SQL,而不仅仅是我们关心的 CURSOR。为了使之仅应用到我们关注的 CURSOR,就必须将该游标隔离在自己的程序中。此外,CURRENTDATA(YES) 也是我在上期专栏中提到的悲观技术之一。

其次,特定于 SQL 的技术是使用对游标声明使用 WITH 子句,并为隔离使用 WITH RS。WITH RS 将使 DB2 在包含合格行的各页面上获取一个 S 锁,并聚集这些锁(对于行定位游标非常重要)直至通过 UPDATE WHERE CURRENT OF CURSOR 升级为 X 锁。COMMIT 时,所有 X 锁和任何主要的 S 锁都将被释放。这种方法也是一种悲观技术,将导致升级开销(参见第 1 部分),但至少是特定于 SQL 的。正因如此,我认为它优于 CURRENTDATA(YES)。

如果有人有更好、更乐观的技术,能处理并发更新程序造成的数据完整性泄漏问题,请与我分享,以便我与其他用户分享。





回页首


V9 的内置时间戳

在第 1 部分中,我们讨论了为表添加一个更新时间戳列,以便在每次更新行时,通过检查这一列来观察是否有更改。但维护时间戳的负担将由程序员承担。如果有人进入 SPUFI 并更新了航,时间戳可能不会发生变化。规则可能不会被遵守。

在 V9 中,我们有了全新的 SQL 语法,用于自动更新的时间戳。您现在可以创建/更改表,并包含一条 ROW CHANGE TIMESTAMP。列的名称可任意指定(MY_UPD_TIMESTAMP),但列的定义包含新参数:GENERATED ALWAYS FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP。现在,程序代码可使用乐观 UPDATE TIMESTAMP 技术(参见第 1 部分),而无需担心其他应用程序(例如 SPUFI 或 QMF)违背规则。





回页首


乐观地坚持

如果说我希望每一名程序员的头脑中都牢记一件事,那么我要说,指出何时应该或不应该保持锁、何时存在或不存在数据完整性泄漏是复杂、令人迷惑、痛苦的过程。尽可能地使用一种方法有许多好处。只要这种技术不适用,就应选择可用选项中最乐观的一种。





回页首


参考资料



关于作者

Bonnie Baker 是一名顾问兼企业培训师,专攻 DB2 for z/OS 平台的应用程序性能问题。作为 IBM DB2 金牌顾问、五届 IDUG Best Speaker 奖项获得者、IDUG Speaker 名人堂成员,她因主办“Things I Wish They'd Told Me 8 Years Ago”系列研讨会和撰写本专栏闻名于世。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款