`
evoleht
  • 浏览: 98668 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于DB2 数据库并发性(3)

    博客分类:
  • DB2
阅读更多

 

乐观锁定是与悲观锁定相对应的,所以要谈乐观锁定,就不可避免的要谈谈什么是悲观锁定,什么是乐观锁定?

 

所谓悲观锁定,就是查询表之后和尝试搜索的更新或删除记录操作之间的时间段挂起锁定的一种锁定策略。我们假设有这样一个场景,见图 56:



悲观锁定策略是:用户使用 RR/RS 隔离级别执行 SELECT 操作或以排他 exclusive 模式锁定表并执行查询操作(这里举例说明),通过游标得到一个结果集——对结果集记录加锁或者锁表,然后遍历这个游标,对这个结果集的每条记录做进一步的判断,符合条件的做更新操作,不符合条件的跳过,一直到游标遍历结束后,执行 COMMIT 操作,释放由 SELECT 操作获得的锁以及更新操作获得的锁,见图 57:



图 57. 悲观锁定策略

悲观锁定的优点就是能够保证实现一致且安全的更改。但是这种锁定策略的主要缺点就是在数据处理期间,一直占据着资源——被处理的资源的锁生命周期比较长,这样的话,可能会降低数据库的并发性,对于具有大并发用户的系统,需要等待资源释放的概率则会增加。

 

乐观锁定 是一项技术,它用于在选择 (SELECT) 行与更新或删除行之间未拥有行锁定的数据库应用程序。应用程序乐观地假定在更新或删除操作前未锁定的行不可能更改。如果行更改,那么更新或删除操作将失败,并且应用程序逻辑将通过重试查询操作(此处是举例说明)来处理这种故障。乐观锁定策略的主要优点是最小化给定资源对于其他事务的不可用时间,因此,它具有比悲观锁定更好的并行性,因为其他应用程序可以读写该行。它的一个缺点是应用程序中需要有更多的重试逻辑。

基于上述同样的场景,乐观锁定的策略是用户使用 CS/RS 隔离级别执行 SELECT 操作(此处是举例说明),得到一个结果集存放到客户端,然后执行 COMMIT 操作,释放对资源的锁定,然后在客户端遍历这个结果集,对这个结果集中的每条数据做进一步的判断,符合条件的做更新操作(如果确实这一行已经被修改了,那么更新操作将失败,应用程序逻辑将处理这些失败,例如,重新尝试查询),不符合条件的跳过,一直到遍历结束,执行 COMMIT 操作,释放相关资源上的锁,见图 58:



图 58. 乐观锁定策略

DB2 V9.5 之前版本的 DB2 应用程序只能通过构建搜索式 UPDATE 语句启用按值乐观锁定,该语句查找具有与所选值完全相同的值的行。如果行的列值已更改,那么搜索式 UPDATE 语句将失败。但是,按值乐观锁定具有一些缺点:

  • 标识主动错误信息,这可能会更新错误的行
  • 构建 UPDATE 搜索条件对应用程序来说很复杂
  • DB2 服务器根据值来搜索目标行的效率不高
  • 某些客户机类型与数据库类型之间的数据类型不匹配,例如,时间戳记不允许在搜索式 UPDATE 中使用所有列。

 

在 DB2 V9.5 之前,乐观锁定是按值乐观锁定,完全由应用程序本身逻辑控制实现的,而从 DB2 V9.5 开始支持增强的乐观锁定,除了应用程序本身逻辑控制实现之外,DB2 本身还提供了一些增强的机制来提高执行的效率。

DB2 V9.5 增加了速度更快的乐观锁定的支持,这种乐观锁定不会产生主动错误信息(误判),

DB2 V9.5 的乐观锁定特性最小化了给定资源对于其他事务的不可用时间,进一步改善了并发性。这一支持通过如下所示的新 SQL 函数、表达式和特性实现的:

  • 行标识符(RID_BITRID)内置函数:该内置函数可用于 SELECT 结果列表或谓词语句。例如,在谓词 WHERE RID_BIT(tab)=? 中,RID_BIT 等于谓词被实现为一种新的直接访问方法(避免了表扫描),从而可以更有效地定位行。在以前,被称为值乐观锁定的技术确定值的方式为:将所有选择(SELECT)的列值添加到谓词,然后应用某些惟一的列组合来筛选出单个行,这种通过表扫描方式访问方法效率较低。
  • ROW CHANGE TOKEN表达式:这种新的表达式返回一个标记作为 BIGINT 。这个标记表示某一行的修改序列中的一个相对点。应用程序可以将某行的当前行更改标记值与上次取回行时保存的行更改标记值进行比较,以判断行是否发生修改。表需要定义一个行修改时间戳列来保存时间戳值,是否提供行修改时间戳列将影响乐观锁定的行为,因为该列有助于将行更改标记的粒度从页级别提高到行级别,这对乐观锁定应用程序非常有利。

使用这种编程模型的应用程序将从增强的乐观锁定特性中获益。

 

在 DB2 V9.5 中,对普通的表即可使用针对乐观锁定的新 SQL 表达式和属性,但是,如果对普通的表不进行 DDL 修改的情况下,乐观锁定应用程序可能会产生更多的漏判。因此,要避免发生漏判,执行乐观锁定的目标表应执行以下任意一种操作来增加 ROW CHANGE TIMESTAMP 列:

  • 创建表时定义 ROW CHANGE TIMESTAMP 列
  • 对表进行修改以包含 ROW CHANGE TIMESTAMP 列

要在应用程序中启用增强的乐观锁定支持,需要执行以下基本步骤:

  • 在初始查询中,对要进行处理的所有行的行标识符和行更改标记执行 SELECT(使用 RID_BIT() 和 RID() 内置函数),使它们被包含在查询列表中。
  • 释放行锁定,以便其他应用程序可以对表执行选择、插入、更新和删除操作。
  • 通过在搜索条件中使用行标识符和行更改标记对目标行执行搜索式 UPDATE 或 DELETE,并乐观地假定在执行原始查询语句后未锁定的行尚未更改。
  • 如果行已更改,那么更新操作将失败,并且应用程序逻辑必须处理该故障。例如,应用程序将重试查询和更新操作。
注:行标识符、行更改标记的用途如下
        —搜索行标识符以直接访问目标行,而不是通过全表扫描或者索引扫描
        —搜索行更改标记以确认行的状态,即如果行更改标记没变,表明相应记录未被任何事务更改,
        反之表明记录已经被更改。
			

 

针对乐观锁定设计并已启用乐观锁定的应用程序,将按照下列操作顺序向数据库发送请求:



 

 
SELECT SALARY, row change token FOR STAFF, RID_BIT(STAFF) 
 INTO :h_SALARY, :h_rct, :h_rid 
 FROM STAFF WHERE ID = 240

 

在此方案中,应用程序首先读取所需的每行。我们准备在应用程序中使用乐观锁定策略,所以选择列表包括保存在 :h_rid 主变量中的行标识符值和保存在 :h_rct 主变量中的行更改标记值,见清单1

在启用了乐观锁定的情况下,应用程序乐观地假定更新或删除操作的任何目标行都保持不变。为了提高数据库并行性,应用程序使用下列其中一种方法除去行锁定:

  • 落实工作单元,在这种情况下行锁定将被除去
  • 使用 WITH RELEASE 子句关闭游标,在这种情况下行锁定将被除去
  • 使用较低的隔离级别:
    • 游标稳定性(CS),在这种情况下,在游标访存到下一行或结果表末尾后行未锁定。
    • 未落实的读(UR),在这种情况下,任何未落实的数据将具有新的(未落实)行更改标记值。如果回滚未落实的数据,那么已落实的旧行更改标记将是另一个值。

注: 假定通常不回滚更新,使用 UR 将允许最大并行性。

  • 断开与数据库的连接,因此释放应用程序的所有 DB2 服务器资源。

在释放查询操作所带来的行锁定之后,在应用程序逻辑中可能对上述查询获得的结果集进行相关判断处理,得到想要继续向下处理的行的行标识符和行更改标记,然后应用程序乐观地更新这些行:



 

UPDATE STAFF SET SALARY = SALARY * 1.2 WHERE row change token 
FOR STAFF = :h_rct AND RID_BIT(STAFF) = :h_rid

 

通过行标识符、行更改标记对目标行进行 UPDATE 是最快的访问方案,因为避免了对表进行扫描,而通过直接访存的方式(通过 ROWID 直接定位到该行):

				 RID_BIT(STAFF) = :h_rid

 

如果 RID_BIT() 谓词未找到行,那么表示行已删除并且更新操作由于未找到行而失败。

假定 RID_BIT() 谓词找到了行,那么在行更改标记未更改时,行更改标记谓词 FOR STAFF = :h_rct 将找到该行。如果在查询操作后行更改标记已更改,那么 UPDATE 语句将由于未找到行而失败。

下表总结了应用程序在启用了乐观锁定之后,可能出现的一些情况。



 

情况标识 操作 结果
情况 1 表中定义了行更改时间戳记列,并且其他应用程序未更改行。 由于行更改标记谓词成功找到 :h_rid 所标识的行,所以更新操作成功。
情况 2 表中定义了行更改时间戳记列。另一个应用程序在查询操作后在更新操作前更新了行,从而更新了行更改时间戳记列。 在查询操作时获得的行更改标记与行中当前行更改标记不匹配,因此 UPDATE 语句找不到行。
情况 3 表中定义了行更改时间戳记列。另一个应用程序更新了行,因此行具有新的行更改标记。此应用程序使用隔离级别 UR 查询行,并获取未落实的新的行更改标记。 此应用程序运行 UPDATE 语句,这将锁定等待,直到其他应用程序释放其行锁定为止。如果其他应用程序使用新标记落实更改,那么行更改标记谓词将成功,因此 UPDATE 语句成功。如果其他应用程序回滚到旧标记,那么行更改标记谓词将失败,因此 UPDATE 语句找不到行。
情况 4 表中未定义任何行更改时间戳记列。在查询操作后在更新操作前,在同一页面上更新、删除或插入了另一行。 该页面上的所有行共享一个行更改标记,该页面上任何行的更新,都会导致此页面上所有行的行更改标记更新。由于该页面上所有行的行更改标记值已更改,因此 UPDATE 语句匹配不到行。
如果本场景中添加了行更改时间戳记列,那么 UPDATE 语句将成功更新目标行。
情况 5 改变 (ALTER) 了表以便包含行更改时间戳记列,并且在改变操作后查询返回的行还未修改。另一个应用程序更新该行,从而在此过程中将行更改时间戳记列添加至该行(具有当前时间戳记)。 行更改标记谓词将先前生成的标记值与根据行更改时间戳记列创建的标记值进行比较,因为找不到匹配行,因此 UPDATE 语句执行失败。
情况 6 在查询操作后在更新操作前重组了表。 :h_rid 所标识的行标识找不到行,或者它包含具有另一个标记的行(经过重组,已经不是原来的那行),因此更新操作失败。这是无法避免的被动错误信息情况。 记录本身未被重组操作更新,记录中所有的列值并未变化,只是记录的位置发生了变更,因此重组后谓词的 RID_BIT 部分无法标识原始行(实际上 UPDATE 语句根据行标识符、行更改标识无法匹配到行),因此 UPDATE 操作失败。

 

 

假设有这样的一个场景:2 个数据库管理员同时接收到某个职员的请求,职员要求将自己的工作岗位变更一下。于是两名 DBA(DBA1/DBA2)通过人力资源系统更新 SAMPLE 数据库的 STAFF 表中的员工记录。此时存在一种可能,即两个 DBA 可能同时对同一名职员的记录进行更新。下面设计了几个场景,针对表 7 中所有的情况进行演示。

 

STAFF 表包含一个 ROW CHANGE TIMESTAMP 列 TS(后来添加)并且只有 DBA1 访问了该表。 DBA1 从 STAFF 表中查询数据并在稍后尝试将 ID 为 70 的员工的工作从 Sales 更新为 Mgr 。更新成功。


 

			
ALTER TABLE STAFF ADD COLUMN TS TIMESTAMP NOT NULL 
GENERATED ALWAYS FOR EACH ROW ON UPDATE AS 

ROW CHANGE TIMESTAMP




 

 
通过查询得到结果集的行标识符、时间标识符 , 然后执行 COMMIT 操作。
SELECT RID_BIT(STAFF),ROW CHANGE TOKEN FOR STAFF,ID,NAME,DEPT,JOB,TS
 FROM STAFF WHERE ID=70 
 COMMIT




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A000006000000000000000000FCF84F' 74904229642240 70 Rothman 15 Sales 0001-01-01-00.00.00.000000




 

 
使用 DBA1 之前查询出来的行标识符、时间标识符来更新行。
UPDATE STAFF SET JOB = 'Mgr' 
 WHERE RID_BIT(STAFF)=x'0A000006000000000000000000FCF84F' 
 AND ROW CHANGE TOKEN FOR STAFF=74904229642240




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A000006000000000000000000FCF84F' 141401933370756520 70 Rothman 15 Mgr 2009-07-02-15.10.17.921000

 

 

STAFF 表包含一个 ROW CHANGE TIMESTAMP 列 TS,并且 DBA1 和 DBA2 同时访问该表。 DBA1 从 STAFF 表中查询数据并执行提交操作,稍后尝试更新这些数据。然而,在 DBA1 查询数据到执行更新操作期间,DBA2 对相同的记录进行了更新。 DBA2 执行的更新成功,而随后 DBA1 执行的更新失败。



 

ALTER TABLE STAFF ADD COLUMN TS TIMESTAMP NOT NULL GENERATED
 ALWAYS FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A00400B00000000000000000465A5C1' 141401934713623382 70 Rothman 15 Mgr 2009-07-02-15.30.18.562006




 

 UPDATE STAFF SET JOB = 'Engineer' WHERE ID=70 
 OR 
 UPDATE STAFF SET JOB = 'Engineer' 
 WHERE RID_BIT(STAFF)= x'0A00400B00000000000000000465A5C1' 
 AND ROW CHANGE TOKEN FOR STAFF=141401934713623382




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A00400B00000000000000000465A5C1' 141401934875088080 70 Rothman 15 Engineer 2009-07-02-15.32.44.546000




 

 
使用 DBA1 之前查询得到的行标识符、时间标识符来更新行。
UPDATE STAFF SET JOB = 'Engi' 
 WHERE RID_BIT(STAFF)= x'0A00400B00000000000000000465A5C1' 
 AND ROW CHANGE TOKEN FOR STAFF=141401934713623382

 

DBA1 更新失败。由于 DBA2 执行了 UPDATE,ROW CHANGE TOKEN 发生了改变,因此当 DBA1 把执行查询时取回的标记与 DBA2 执行更新后的标记当前值进行比较时,无法找到匹配行,因此 DBA1 更新失败。

 

STAFF 表包含一个 ROW CHANGE TIMESTAMP 列 TS,并且 DBA1 和 DBA2 同时访问该表,DBA1 对行进行了更新,但还未提交修改,DBA2 使用 UR 隔离级别从 STAFF 表中查询数据,接着 DBA1 提交它做出的修改,然后 DBA2 尝试对相同的数据进行更新,DBA2 执行更新能够成功,因为 DBA2 之前执行脏读查询读取的是 DBA1 未提交的更新,这时变化后的 ROW CHANGE TOKEN 被读取到(当 DBA1 后来执行提交操作时,提交前产生变化的 ROW CHANGE TOKEN 不会再发生改变),所以后来 DBA2 执行更新操作能够找到匹配行,执行更新成功。然而,如果 DBA1 回滚更新操作而不是提交更新操作,那么 DBA2 的更新操作将失败。



 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A00000600000000000000000465ABC4' 141401934875088080 70 Rothman 15 Mgr 2009-07-02-15.32.44.546000




 

 UPDATE STAFF SET JOB = 'Chief' 
 WHERE RID_BIT(STAFF)= x'0A00000600000000000000000465ABC4' 
 AND ROW CHANGE TOKEN FOR STAFF=141401934875088080




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A00000600000000000000000465ABC4' 141401936241179608 70 Rothman 15 Chief 2009-07-02-15.53.03.343000

 

然后 DBA1 提交之前执行的 UPDATE 语句



 

commit

 

表 14. DBA1 查询提交后的结果

可以发现时间标识符与 DBA2 查询到的一致,实际上反映的都是新的时间标识符(不管是否提交)。

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A00000600000000000000000465ABC4' 141401936241179608 70 Rothman 15 Chief 2009-07-02-15.53.03.343000




 

 UPDATE STAFF SET JOB = 'GM' WHERE ID=70 
 OR 
 UPDATE STAFF SET JOB = 'GM' 
 WHERE RID_BIT(STAFF)= x'0A00000600000000000000000465ABC4' 
 AND ROW CHANGE TOKEN FOR STAFF=141401936241179608




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0A00000600000000000000000465ABC4' 141401937033810064 70 Rothman 15 GM 2009-07-02-16.00.55.250000

 

 

STAFF 表不包含 ROW CHANGE TIMESTAMP 列。 DBA1 查询一行 (ID=70),获得 ROW CHANGE TOKEN/RID_BIT(),然后 DBA2 更新了同一数据页中的其他记录 (ID=110, 这时 ROW CHANGE TOKEN 将发生改变,这个页中所有记录的 ROW CHANGE TOKEN 都是一样的,这时 ROW CHANGE TOKEN 是基于页的 ),然后,DBA1 尝试更新之前查询到的记录(通过 ROW CHANGE TOKEN/RID_BIT() 来定位),更新将会失败,因为 ROW CHANGE TOKEN 已经发生了改变,找不到匹配的记录了。



 

通过查询得到结果集的行标识符、时间标识符 , 然后执行 COMMIT 操作。
SELECT RID_BIT(STAFF),ROW CHANGE TOKEN FOR STAFF,ID,NAME,DEPT,JOB 
FROM STAFF WHERE ID = 70 
 COMMIT
 




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB
x'0A00400B00000000000000000465EFF9' 7632868011317133312 70 Rothman 15 Mgr

 

表 17. 同一数据页面上还存在的其他一些记录

下面几条记录都属于同一数据页面。

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB
x'0B00400B00000000000000000465EFF9' 7632868011317133312 80 James 20 Clerk
x'0C00400B00000000000000000465EFF9' 7632868011317133312 90 Koonitz 42 Sales
x'0D00400B00000000000000000465EFF9' 7632868011317133312 100 Plotz 42 Mgr
x'0E00400B00000000000000000465EFF9' 7632868011317133312 110 Ngan 15 Clerk




 

			
更新同一数据页面上的另外一条记录 (ID=110)
UPDATE STAFF SET JOB = 'Mgr' WHERE ID=110

 

表 18. DBA2 执行 UPDATE 语句后的结果

下表为同一数据页面上的部分记录,可以看到虽然只更新了ID=110这条记录,但是此页面上所有记录的 ROW CHANGE TOKEN 都共享 ID=110 这条记录的 ROW CHANGE TOKEN,也就是说表在没有时间戳记列存在的情况下,ROW CHANGE TOKEN 是基于页存在的。

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB
x'0A00400B00000000000000000465EFF9' -1300866274502377472 70 Rothman 15 Mgr
x'0B00400B00000000000000000465EFF9' -1300866274502377472 80 James 20 Clerk
x'0C00400B00000000000000000465EFF9' -1300866274502377472 90 Koonitz 42 Sales
x'0D00400B00000000000000000465EFF9' -1300866274502377472 100 Plotz 42 Mgr
x'0E00400B00000000000000000465EFF9' -1300866274502377472 110 Ngan 15 Clerk




 

			
通过之前查询得到的 ROW CHANGE TOKEN/RID_BIT() 定位。
 UPDATE STAFF SET JOB = 'Clerk' 
 WHERE RID_BIT(STAFF)= x'0A00400B00000000000000000465EFF9' 
 AND ROW CHANGE TOKEN FOR STAFF=7632868011317133312
 
 

 

更新将失败,已经找不到匹配的记录了,因为整个页面的时间标识符已经由于 DBA2 执行 UPDATE 语句而改变了。

 

STAFF 表包含 ROW CHANGE TIMESTAMP 列 TS,DBA1 和 DBA2 访问该表。 DBA1 从中查询一行,然后 DBA2 更新了同一数据页中的另外一行,接着 DBA1 更新之前查询到的那条记录,更新可以成功。



 

通过查询得到结果集的行标识符、时间标识符 , 然后执行 COMMIT 操作。
SELECT RID_BIT(STAFF),ROW CHANGE TOKEN FOR STAFF,ID,NAME,DEPT,JOB,TS 
FROM STAFF WHERE ID=120 
 COMMIT




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0F0000060000000000000000055F4927' 141402635178433027 120 Naughton 38 Clerk 2009-07-07-18.36.01.875011

 

表 20. 同一数据页面上还存在的其他一些记录

下面几条记录都属于同一数据页面。

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB
x'0B0000060000000000000000055F4927' 141402635178433023 80 James 20 Clerk
x'0C0000060000000000000000055F4927' 141402635178433024 90 Koonitz 42 Sales
x'0D0000060000000000000000055F4927' 141402635178433025 100 Plotz 42 Mgr
x'0E0000060000000000000000055F4927' 141402635178433026 110 Ngan 15 Clerk




 

更新同一数据页面上的另外一条记录。
 UPDATE STAFF SET JOB = 'VP' 
 WHERE RID_BIT(STAFF)= x'0D0000060000000000000000055F4927' 
 AND ROW CHANGE TOKEN FOR STAFF=141402635178433025




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0D0000060000000000000000055F4927' 141402635937539040 100 Plotz 42 VP 2009-07-07-18.47.21.812000




 

 
通过之前查询得到的 ROW CHANGE TOKEN/RID_BIT() 定位,更新成功。
UPDATE STAFF SET JOB = 'Mgr' 
 WHERE RID_BIT(STAFF)= x'0F0000060000000000000000055F4927' 
 AND ROW CHANGE TOKEN FOR STAFF=141402635178433027




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'0F0000060000000000000000055F4927' 141402643285428659 120 Naughton 38 Mgr 2009-07-07-20.28.53.281011

 

 

STAFF 表具有一个 ROW CHANGE TIMESTAMP 列 TS,并且只有 DBA1 访问该表。 DBA1 先从中查询一条记录用于以后更新它。然后表被离线重组。最后 DBA1 尝试更新数据,更新失败。更新失败是因为执行 REORG 后 RID_BIT 指向的已经不是原来的那一条记录,而且所有记录的 ROW CHANGE TIMESTAMP 列值也发生了变化,所以 DBA1 根据之前查询得到的 RID_BIT/ROW CHANGE TOKEN 已经找不到匹配的行,所以更新失败。



 

通过查询得到结果集的行标识符、时间标识符 , 然后执行 COMMIT 操作。
SELECT RID_BIT(STAFF),ROW CHANGE TOKEN FOR STAFF,ID,NAME,DEPT,JOB,TS 
FROM STAFF WHERE ID=150 
 COMMIT




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'1200400B00000000000000000465EFF9' 74904229642240 150 Williams 51 Sales 0001-01-01-00.00.00.000000




 

 REORG TABLE STAFF




 

乐观锁定表达式 STAFF 表
RID_BIT ROW CHANGE TOKEN ID NAME DEPT JOB ROW CHANGE TIMESTAMP
x'12000006000000000000000004A3C230' 141401962414435156 150 Williams 51 Sales 2009-07-02-21.59.04.093012

 

可以发现ID=150这条记录已经被移动到别的页面上去了,因为 RID_BIT() 已经发生了变化,而且 ROW CHANGE TOKEN 也发生了变化。



 

 
根据之前查询得到的行标识符、行更改标记执行更新操作,很明显,更新操作不能成功。
即使行标识符可能仍然指向有效的记录(已经不是原来的那条记录,因为这个位置可能已经被新的记录所占据),
但是行更改标记也已经发生了改变,所以使用之前查询得到的行标识符、行更改标记进行匹配,
匹配不到记录,所以更新操作不能成功。
UPDATE STAFF SET JOB = 'Mgr' 
 WHERE RID_BIT(STAFF)= x'1200400B00000000000000000465EFF9' 
 AND ROW CHANGE TOKEN FOR STAFF=74904229642240

 

结束语

 

为了避免在使用悲观锁定技术时可能引发的锁等待而导致的并发性问题,乐观锁定技术最小化了给定资源对于其他事务的不可用时间。通过使用乐观锁定,数据库管理器在完成读操作之后可以立即释放锁。

DB2 V9.5 支持更高效的乐观锁定,而且避免了误判的发生。这些支持通过行标识符(RID_BIT 或 RID)内置函数、行更改标识符 (ROW CHANGE TOKEN 表达式 ) 实现的。使用这种编程模型的应用程序可以从增强的乐观锁定特性受益,并且能够进一步增强并发性。

<!-- CMA ID: 419144 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-document-html-6.0.xsl -->

 

 

原文地址:http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0908renzg/

分享到:
评论

相关推荐

    DB2数据库性能调整和优化 牛新庄 PDF

    深刻理解DB2的锁及并发机制、索引原理、数据库参数、优化器原理、SQL语句调优等内部机理才能针对性地快速提出解决问题的方法;快照、db2pd、db2expln及事件监控器等则是必须熟练掌握的工具。《DB2数据库性能调整和...

    一个关于DB2数据库学习文档集

    DB2数据库是一款由IBM开发的关系型数据库管理系统,广泛应用于企业级的数据存储和管理。这个文档集是针对DB2的学习资源,包含了多个方面的内容,对于深入理解和掌握DB2有着极高的价值。 首先,DB2函数文档详细列出...

    DB2的并发性 DB2的并发性

    ### DB2并发性的深入解析 #### 一、并发性概述 在多用户环境中,数据库管理系统(DBMS)必须处理多个用户同时访问和修改同一数据库的情况。这种情况被称为“并发性”。DB2作为一款强大的企业级数据库管理系统,提供...

    DB2数据库基础学习

    ### DB2数据库基础学习 #### 一、DB2数据库概览 DB2是IBM公司开发的一款关系型数据库管理系统,自1983年发布以来,不断进化,支持多种平台,包括Windows、Linux、Unix和z/OS等。DB2不仅提供高性能的数据存储和检索...

    DB2数据库程序开发试验

    DB2数据库程序开发试验是一个深度探索数据库管理系统的实践性学习项目,主要针对吉林大学软件学院的学生。这个试验涉及使用IBM的DB2_ESC_97_x64版本,这是一个64位的企业级数据库管理系统,适合大规模数据存储和处理...

    db2数据库面试问题

    根据给定文件中的标题、描述、标签以及部分内容,我们可以从中提炼出与DB2数据库相关的多个重要知识点。以下是对这些知识点的详细阐述: ### DB2数据库面试问题概览 #### 1. E-R图中的关系类型及其特点 E-R图...

    db2数据库性能优化小技巧

    锁机制是数据库并发控制的重要手段之一,不合理的锁设置可能会导致性能瓶颈。 #### 3.1 锁列表配置 - **Lock List Memory**:锁列表内存,用于存储锁定信息。如果锁列表内存不足,可能会导致锁等待时间延长,影响...

    IBM内部关于DB2数据库的中文翻译版资料

    从给定的文件信息来看,这是一份关于IBM DB2数据库管理与开发的GUI界面操作指南,名为“db2atc80管理和开发GUI.pdf”。这份文档提供了详细的指导,涵盖了DB2数据库的各种功能和操作流程,是IBM为DB2用户提供的专业...

    db2数据库驱动9.7jar包(全) db2jcc.jar+db2jcc_license_cu.jar

    DB2数据库支持多种特性,如事务处理、并发控制、备份恢复、安全性、性能调优等。9.7版本的改进可能包括更快的查询速度、更高的并发能力、更好的内存管理以及对Java EE 5和6的支持。在开发和部署Java应用程序时,理解...

    DB2数据库管理最佳实践pdf

    这份PDF文档很可能是对DB2数据库在实际操作中的优化策略、配置技巧和故障排查方法的深入探讨,旨在帮助管理员提升DB2的性能、稳定性和安全性。 在DB2数据库管理中,有几个关键的知识点是所有管理员都需要掌握的: ...

    牛新庄-db2数据库性能调整优化

    合理设置事务隔离级别可以平衡并发性和数据一致性,避免死锁的发生。同时,优化事务处理逻辑,减少不必要的回滚和重试,可以显著提升系统吞吐量。 数据库的物理存储布局同样影响性能。通过合理分配表空间、分区和段...

    DB2数据库性能调整和优化

    DB2数据库是IBM公司开发的一款关系型数据库管理系统,广泛应用于企业级数据存储和管理。数据库性能调整和优化是确保系统高效运行的关键环节,涉及到多个层面的技术和策略。本篇文章将深入探讨DB2数据库性能调整与...

    db2数据库错误解决代码sqlcode

    DB2数据库是IBM开发的一款企业级关系型数据库管理系统,广泛应用于大型企业和机构。在使用过程中,用户可能会遇到各种错误,其中“SQLCODE”是DB2返回的一种错误代码,用于指示查询或操作失败的具体原因。本篇文章将...

    【原创】Loadrunner监控DB2数据库

    监控 DB2 数据库是性能测试中的重要环节,它可以帮助我们了解系统在高负载下的表现,找出瓶颈,优化数据库配置,以提升整体系统的稳定性和效率。正确配置 LoadRunner 以监控 DB2,可以提供有价值的数据,支持我们...

    db2数据库驱动jar包

    它支持SQL语言,提供事务处理、并发控制、数据恢复等核心功能,并具有高度的安全性和稳定性。 该驱动jar包的使用主要包括以下几个步骤: 1. **添加依赖**:将下载的db2数据库驱动jar包添加到项目的类路径中,对于...

    DB2 for zOS DB2 数据库设计取得最佳性能的准则

    在IBM的大型主机系统z/OS上,DB2数据库的性能优化是关键任务,因为早期的设计决策会显著影响应用程序和数据库的性能。本文主要针对DB2 for z/OS环境,提供一些数据库设计的通用准则和建议,以提升整体性能。 首先,...

    企业级DB2数据库学习与认证

    "企业级DB2数据库学习与认证"的主题意味着我们将深入探讨DB2的基础知识、高级特性和如何准备IBM的DB2资格认证。 首先,我们要理解DB2的基本概念,包括数据模型、SQL语言以及数据库管理系统的核心功能。DB2遵循标准...

    DB2数据库基础与应用开发

    - **第6部分:数据并发性** - 讲解数据一致性的重要性及其在单用户和多用户环境中的维护机制。 - 探讨事务处理和锁机制等主题。 - **第7部分:XQuery简介** - 介绍XQuery的基础概念。 - 学习如何编写简单的...

Global site tag (gtag.js) - Google Analytics