DB2 锁问题分析与解释

DB2 应用中经常会遇到锁超时与死锁现象,那么这种现象产生的原因是什么呢。本文以试验的形式模拟锁等待、锁超时、死锁现象,并给出这些现象的根本原因。

试验环境:

DB2 v9.7.0.6
AIX 6.1.0.0
采用默认的隔离级别CS

STUDENT表的DDL与初始内容
------------------------------------------------
-- DDL Statements for table "E97Q6C  "."STUDENT"
------------------------------------------------
 
CREATE TABLE "E97Q6C  "."STUDENT"  (
                  "AGE" INTEGER , 
                  "NAME" CHAR(8) )   
                 IN "USERSPACE1" ;

$ db2 "select * from student"

AGE         NAME    
----------- --------
          3 xu      
          5 gao     
          2 liu     
          1 gu

试验1:验证insert操作与其他操作的锁等待问题

session 1中发出insert操作,在session 2中观察insert,update,delete操作是否会锁超时。

session 1
---------
$ db2 +c "insert into student values(4, 'miao')"
DB20000I  The SQL command completed successfully.

session 2
---------
$ db2 "insert into student values(6, 'mu')"
DB20000I  The SQL command completed successfully.
$ db2 "update student set name='gu' where age=1"
DB20000I  The SQL command completed successfully.
$ db2 "delete from student where age=2"
DB20000I  The SQL command completed successfully.

----------------------------------------------------------------------------

结论1:当session 1对表作insert操作时,session 2对该表的insert及其他行的update,delete操作都不会有问题

----------------------------------------------------------------------------

试验2:验证update操作与其他操作的锁等待问题
session 1中发出update操作,在session 2中观察insert,update,delete操作是否会锁超时。
--------------
session 1
---------
$ db2 commit

$ db2 "select * from student"

AGE         NAME    
----------- --------
          3 xu      
          5 gao     
          6 mu      
          4 miao    
          1 gu

5 record(s) selected.

$ db2 +c "update student set name = 'qing' where age=4"
DB20000I  The SQL command completed successfully.

session 2
---------
$ db2 "insert into student values(6, 'mu')"
DB20000I  The SQL command completed successfully.
$ db2 "update student set name='gu' where age=1"
DB21034E  The command was processed as an SQL statement because it was not a 
valid Command Line Processor command.  During SQL processing it returned:
SQL0911N  The current transaction has been rolled back because of a deadlock 
or timeout.  Reason code "68".  SQLSTATE=40001
$ db2 "delete from student where age=2"
DB21034E  The command was processed as an SQL statement because it was not a 
valid Command Line Processor command.  During SQL processing it returned:
SQL0911N  The current transaction has been rolled back because of a deadlock 
or timeout.  Reason code "68".  SQLSTATE=40001

----------------------------------------------------------------------------
结论2:当session 1对表某一行做update操作时,session 2可以对该表作insert操作,但不允许对其他行的delete和update操作
----------------------------------------------------------------------------

试验3:验证delete操作与其他操作的锁等待问题
session 1中发出delete操作,在session 2中观察insert,update,delete操作是否会锁超时。

Session 1
---------
$ db2 commit

$ db2 +c "delete from student where age=4"
DB20000I  The SQL command completed successfully.

session 2
---------
$ db2 "insert into student values(6, 'mu')"
DB20000I  The SQL command completed successfully.

$ db2 "update student set name='gu' where age=1"
DB21034E  The command was processed as an SQL statement because it was not a 
valid Command Line Processor command.  During SQL processing it returned:
SQL0911N  The current transaction has been rolled back because of a deadlock 
or timeout.  Reason code "68".  SQLSTATE=40001

$ db2 "delete from student where age=2"
DB21034E  The command was processed as an SQL statement because it was not a 
valid Command Line Processor command.  During SQL processing it returned:
SQL0911N  The current transaction has been rolled back because of a deadlock 
or timeout.  Reason code "68".  SQLSTATE=40001
----------------------------------------------------------------------------
结论3:当应用1对表某一行做delete操作时,应用2可以对该表作insert操作,但不允许对其他行的delete和update操作
----------------------------------------------------------------------------

总的结论是:
应用对表作insert操作时,其他操作不受影响,也不受其他操作影响。
作update,delete操作时,其他的update和delete操作受影响。

为了解释以上现象的原因,我们首先看一下上面的操作需要什么样的锁。

session 1.
---------
$ db2 rollback

$ db2 +c "insert into student values(7,'han')"
DB20000I  The SQL command completed successfully.

$ db2pd -db qsmiao -locks

结论:insert操作需要表级的IX锁和行级的X锁。
注:IX锁,该锁的拥有者在拥有相应行的X锁时可以更改该行的数据。

$ db2 rollback

$ db2 +c "update student set name='yan' where age=5"
DB20000I  The SQL command completed successfully.

$ db2pd -db qsmiao -locks

结论:update操作需要表级的IX锁和行级的X锁。

$ db2 rollback

$ db2 +c "delete from student where age=6"

DB20000I  The SQL command completed successfully.

$ db2pd -db qsmiao -locks

结论:update操作需要表级的IX锁和对应的行级的X锁(这里因为3条记录的age都为6,因此需要3个行级锁)。

现在的问题是:为什么insert和update,delete操作需要的锁一样(表级的IX锁,对应行级的X锁),但是表现的效果却不一样呢?

为了解决这个问题,看一下他们的执行计划吧:

$ db2expln -d qsmiao -g -statement "insert into student values(5, 'gao')" -terminal

$ db2expln -d qsmiao -g -statement "update student set name='qing' where age=4" -terminal

$ db2expln -d qsmiao -g -statement "delete from student where age=6" -terminal

从上面的执行计划中可以看到原因:insert操作不需要表扫描,而update和delete操作都需要全表扫描,而且会在扫描的时候试图对每一行加U锁。
导致锁超时的原因就是表扫描
例如session 1要更新表的某一行,会在该行加上X锁。之后, session 2试图更新该表的另一行,进行全表扫描时,就会试图对A占用的那一行加上U锁,但无能为力,最终导

致锁超时。

为了验证该说法,可以抓取锁等待的消息,

session 1
---------
$ db2 +c "update student set name='hehe' where age = 4"
DB20000I  The SQL command completed successfully.

session 2
---------
$ db2 +c "delete from student where age=6"
       <-------这时会hang住,因为它在等session 1的锁

session 3
---------
$ db2pd -db qsmiao -wlocks  <---在锁超时发生之前,抓取锁等待的消息

Locks being waited on :
AppHandl [nod-index] TranHdl    Lockname                                   Type       Mode Conv Sts      CoorEDU  AppName  AuthID   AppID                           
15393    [000-15393] 2               00020004000000000000000952 Row        ..X       G    7818       db2bp    E97Q6C   *LOCAL.e97q6c.141016035113       
15408    [000-15408] 16             00020004000000000000000952 Row        ..U       W   10153      db2bp    E97Q6C   *LOCAL.e97q6c.141016035219

可以看到,是因为U锁和X锁的不兼容导致锁等待,最后导致锁超时。

为了解决该锁等待问题,可以在查询谓词所涉及的列age上建立索引,避免全表扫描

试验4:通过建立索引,消除锁等待现象

session 1
---------
$ db2 rollback

$ db2 +c "lock table student in share mode"

$ db2 +c "create index stu_idx on student(age)"

$ db2 commit

$ db2 +c "update student set name='hehe' where age = 4"
DB20000I  The SQL command completed successfully.

session 2
---------
$ db2 +c "delete from student where age=6"  <--没有发生锁等待现象,直接成功
DB20000I  The SQL command completed successfully.

可以看到,已经通过索引解决了该锁超时问题,如果读者有兴趣的话,可以看下建立索引之后的访问计划。

下面模拟一个死锁现象
试验5:模拟死锁,过程如下
第一步:session 1 获得 锁 LOCK1

第二步:session 2 获得 锁 LOCK2

第三步:session 2 申请 锁 LOCK1

第四步:session 1 申请 锁 LOCK2

为了避免死锁之前产生锁超时,先将锁超时控制参数设为-1(表示永远等待)
update db cfg using locktimeout -1
之后重启数据库

session 1
---------
$ db2 +c "update student set name = 'an' where age = 1"       <--获得锁LOCK1,成功
DB20000I  The SQL command completed successfully.

session 2
---------
$ db2 +c "update student set name = 'two' where age = 4"      <--获得锁LOCK2,成功
DB20000I  The SQL command completed successfully.

$ db2 +c "update student set name = 'four' where age = 1"     <--申请锁LOCK1,hang住,因为LOCK1被session 1持有

session 1
---------
$ db2 +c "update student set name = 'three' where age = 4"    <--申请锁LOCK2,hang住,因为LOCK2被session 2持有

这时已经发生了死锁,10s之后,这两个session有一个会报出如下死锁(reason code 2)错误,另一个session成功执行
SQL0911N  The current transaction has been rolled back because of a deadlock 
or timeout.  Reason code "2".  SQLSTATE=40001

参考资料:
标准表的锁定方式和存取方案,这里您可以看到详细的加锁方式
http://www-01.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.admin.perf.doc/doc/r0005275.html?lang=zh

附,只能在发生死锁或者锁等待的时候才能用db2pd查看锁的信息。下面附上如何采用事件监控器监控死锁/锁超时。事件监控器可以抓取一段时间内的锁事件
db2 update db cfg for sample using MON_LOCKWAIT hist_and_values MON_DEADLOCK hist_and_values MON_LOCKTIMEOUT hist_and_values MON_LW_THRESH 10000
db2 "CREATE EVENT MONITOR LOCKEVMON FOR LOCKING WRITE TO UNFORMATTED EVENT TABLE (TABLE LOCKEVMON)"
db2 set event monitor LOCKEVMON state=1

重现问题

db2 flush event monitor LOCKEVMON
db2 set event monitor LOCKEVMON state=0

cp /home/db2users/e97q6c/sqllib/samples/java/jdbc/db2evmonfmt.java ./
cp /home/db2users/e97q6c/sqllib/samples/java/jdbc/DB2EvmonLocking.xsl ./
export PATH=/home/db2users/e97q6c/sqllib/java/jdk64/bin:$PATH

javac db2evmonfmt.java

java db2evmonfmt -d sample -ue LOCKEVMON -ftext -u e97q6c -p e97q6c > deadlock.txt
more deadlock.txt 可以看到有关的SQL语句。

请参考

http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-1004lockeventmonitor/

http://blog.csdn.net/qingsong3333/article/details/51206329

DB2 锁问题分析与解释相关推荐

  1. mysql平均锁_MySQL锁情况分析

    TIPS 本文基于MySQL 8.0.22 分析锁的三种方式 方式1: show status like '%innodb_row_lock%'; 可查看行锁相关的统计信息 方式2: SHOW ENG ...

  2. Java多线程:线程8锁案例分析

    线程8锁案例分析 通过分析代码,推测打印结果,并运行代码进行验证 1.两个线程调用同一个对象的两个同步方法 被synchronized修饰的方法,锁的对象是方法的调用者.因为两个方法的调用者是同一个, ...

  3. DB2锁表或超时解决方案

    DB2锁表或超时解决方案 参考文章: (1)DB2锁表或超时解决方案 (2)https://www.cnblogs.com/julygift/p/9401426.html 备忘一下.

  4. oracle degree 造成阻塞_数据库锁/阻塞分析的一种常用方法

    对于一些中小用户来说,日常遇到的最多的问题不外乎表空间与锁的分析.数据库表空间使用率/空间使用率分析似乎很简单,是一条SQL就能搞定的事情,实际上并不简单,这个话题容以后找时间阐述.今天就重点分析下另 ...

  5. ElasticSearch评分分析 explian 解释和一些查询理解

    ElasticSearch评分分析 explian 解释和一些查询理解 按照es-ik分析器安装了ik分词器.创建索引:PUT /index_ik_test.索引包含2个字段:content和nick ...

  6. MySQL锁等待分析【2】

    MySQL锁等待分析[1]中对锁等待的分析是一步一步来的.虽然最后是分析出来了,可是用时是比较长的:理清各个表之间的关系后,得到如下SQL语句,方便以后使用 select block_trx.trx_ ...

  7. informix 数据库锁表分析和解决方法

    informix 数据库锁表分析和解决方法 参考文章: (1)informix 数据库锁表分析和解决方法 (2)https://www.cnblogs.com/kongzhongqijing/arti ...

  8. 【自然语言处理】【可解释性】Perturbed Masking:分析和解释BERT的无参数探针

    Perturbed Masking:分析和解释BERT的无参数探针 Perturbed Masking:Parameter-free Probing for Analyzing and Interpr ...

  9. 功能点(FP)分析详细解释

    –转载 功能点(FP)分析详细解释 Allan J. Albrecht最初于1979年在IBM开发功能点分析, 后来国际功能点用户组(IFPUG)对其进行了进一步的修改. FPA用于估算软件项目, 包 ...

最新文章

  1. 小分子溶液当硬盘!布朗大学逆天研究:用代谢分子存储照片,准确率达99%
  2. python与excel结合-Python与Excel之间的交互
  3. Tomcat中两个不同项目共享Session
  4. optee运行时来了一个REE(linux)中断--代码导读
  5. Service order save debug for distribution lock set logic
  6. c语言 方程改main的值_C语言编程笔记丨编写第一个C语言程序hello world,我教你哇...
  7. LeetCode 1790. 仅执行一次字符串交换能否使两个字符串相等
  8. 如何在不跳转的情况下实现用户登录
  9. 多重异常处理 java
  10. POJ NOI0105-43 质因数分解
  11. 2014青岛初中组第2题 洪水 详解(C++)
  12. 运行java SWT例子
  13. 如何有效阅读英文数据手册?
  14. 在Python中以foo.bar.baz的方式访问嵌套dict中的内容
  15. 浏览器前进后退静默刷新页面
  16. 【软件测试】测试员vs测试工程师,你是测试员还是测试工程师?
  17. CAN节点报文丢失超时时间检测CANoe自动化脚本实现
  18. 无光驱,硬盘安装XP完整原版
  19. Tomcat+Servlet面试题都在这里(修订版)
  20. watermark知识点

热门文章

  1. VS编译器提示:C4996 ‘scanf‘: This function or variable may be unsafe. Consider using scanf_s instead.的解决方法
  2. Python全栈开发【基础二】
  3. BufferedWriter的write(int c)方法
  4. 基于Python+Bootstrap+Django的移动套餐SQL智能检测系统
  5. React Native 中 TextInput 组件和中文输入冲突
  6. scrapy豆瓣爬虫mysql存储名字有图片的问题(关于utf8mb4)
  7. NASA发布NASADEM_HGT及下载方式——从珠穆朗玛峰和天门山说起
  8. Linux学习-67-日志服务器设置和日志分析工具(logwatch)安装及使用
  9. ECHARTS-MAP的使用: 中国地图及省份边界的查看
  10. 药物与生物大分子的相互关系(分子与药物以及人体关系)