• DB2 锁问题分析与解释


    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


  • 相关阅读:
    JavaCV的摄像头实战之一:基础
    JavaCV的摄像头实战之三:保存为mp4文件
    JavaCV的摄像头实战之五:推流
    JavaCV的摄像头实战之二:本地窗口预览
    几行代码把Chrome搞崩溃之:HTML5 MP3录音由ScriptProcessorNode升级成AudioWorkletNode采坑记
    根据经纬度坐标获得省市区县行政区划城市名称,自建数据库 java python php c# .net 均适用
    最新全国省市区县乡镇街道行政区划数据提取(2022年)
    我完成了10000小时开发3D引擎 Wonder
    腾讯云轻量服务器通过Docker搭建外网可访问连接的redis5.x集群
    Maven Helper插件——实现一键Maven依赖冲突问题
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7258920.html
Copyright © 2020-2023  润新知