暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

【达梦干货攻略】DM8锁等待和死锁

达梦大学 2021-01-29
10487
达梦数据库通过多版本并发控制MVCC和锁机制实现事务的并发控制和保持数据的一致性及正确性。在实际工作中,可能出现多个事务同时访问、修改相同数据的情况,当一个事务正在占用某个资源的锁,此时另一个事务正在请求这个资源上与第一个锁相冲突的锁类型时,就会发生阻塞。
本文介绍如何使用动态性能视图查看锁等待以及解决锁阻塞的问题。

本章内容已在如下环境上测试:
①操作系统:中标麒麟7
②数据库版本:达梦DM8
相关关键字:锁等待、 V$LOCK、V$TRXWAIT、死锁、锁超时

DM事务锁
在测试前,新建T_TEST01表,其中ID字段为主键,表结构参考如下:
    create table t_test01(id int primary key, name varchar(20));
    查询该表:
    此时,查询v$lock该表的锁(先查询SYSOBJECTS获取表的ID,使用ID查询该表的锁),可以看到读操作时有IS锁(意向共享锁)。
    打开一个新会话(会话一),在T_TEST01表中插入一条测试数据(未提交):
      insert into t_test01(id, name) values(1, 'cheng');
      此时查看v$lock,新增表对象的IS(意向共享锁)和IX(意向排他锁)

      锁等待

      01

      锁等待测试

      场景一:INSERT锁等待
      当多个事务同时试图向有主键或UNIQUE约束的表中插入相同的数据时,前一个事务未提交,后面的事务将被阻塞,直到前一个事务提交或回滚。

      新增会话二,再插入与会话一相同的数据,因为该表有主键,会话一未提交,此时可以看到会话被阻塞:

      查询v$lock可以看到该对象新增了TID共享锁(S锁),并且该锁BLOCKED=1,该锁被33125(会话一)事务阻塞:
      此时,如果我们提交会话一插入的数据,执行commit;
      再次查询v$lock,可以看到提交之后相关的事务锁已经释放,并且会话二抛出异常:
      场景二:UPDATE和DELETE锁等待
      当UPDATE和DELETE修改的记录已经被另一个事务修改过(未提交),将会发生阻塞,直到未提交的造成阻塞的事务提交或回滚。
      新增会话三:更新id=1的记录:
      新增会话四:删除id=1的记录
      此时查看v$lock 或v$trxwait,可以看到会话被阻塞:


      02

      锁等待解决方法

      上述场景二测试中,如果提交第一次事务,就可以解决锁等待的问题(同场景一)。

      但实际业务中,我们可能无法手工提交阻塞的会话,此时可以强制杀死会话:

      使用如下语句查询处于等待的锁(或查询v$trxwait可以查看阻塞事务):

        select TRX_ID, LTYPE, LMODE, BLOCKED, TABLE_ID, TID 
        from v$lock where blocked=1;

        如上图,根据阻塞的事务ID=33127找到会话ID,可以看到会话id,sql信息:

        根据会话ID,使用sp_close_session系统过程即可杀死会话(也可以使用操作系统命令 kill -9 线程ID杀死线程,上图中THRD_ID为线程ID):

        再次查询v$lock可以看到会话阻塞问题解决:


        死锁
        死锁与阻塞的不同之处在于死锁包括两个或者多个已阻塞事务,它们之间形成了等待环,每个都等待其他事务释放锁。例如事务1给表T1上了排他锁,第二个事务给表T2上了排他锁,此时事务1请求T2的排他锁,就会处于等待状态,被阻塞。若此时T2再请求表T1的排他锁,则T2也处于阻塞状态。此时这两个事务发生死锁,DM数据库会选择牺牲掉其中一个事务。
        测试场景如下:
        新增会话一:对T_TEST01插入一条数据(此时T_TEST01表上有了排他锁)。
        新增会话二:新增T_TEST02表,表结构同T_TEST01,并插入相同数据(此时T_TEST02表上有了排他锁)

        在会话一上往T_TEST02表插入相同数据,因为有主键,产生锁等待:

        在会话二上往T_TEST01表插入相同数据,此时产生死锁,可以看到DM数据库自动检测到死锁的产生,并报出错误:
        死锁的本质也是锁等待,所以解决锁等待的问题,就解决了死锁的问题。

        DDL锁超
        当我们对某张表执行DDL操作时(比如修改某张表的表结构),若当前表上有排他锁(未提交的DML事务),此时数据库会根据锁的等待时间抛出锁超时的异常。
        DM数据库的DDL锁超时时间是由参数DDL_WAIT_TIME指定,默认十秒,可根据实际需要修改。
        锁超时场景测试:
        新增会话一,在T_TEST01表中插入数据(未提交),产生一个排他锁:
          insert into t_test01(id, name) values(2, 'qing');
          新增会话二,执行DDL语句(对t_test01新增字段),此时会话处理等待状态:
            alter table t_test01 add column info1 varchar(50);
            查询v$trxwait可以看到事务处于阻塞等待:
            大概十多秒,会话二抛出锁超时的异常:
            锁超时的本质原因是锁等待,解决锁等待的问题,就解决了锁超时的问题。


            以上是本次干货攻略的分享内容,希望能给大家带来帮助,谢谢。


            往期回顾

            干货攻略丨达梦逻辑导入使用总结

            干货攻略丨达梦SQL优化之LIKE前后百分号
            干货攻略丨DM巧用分区交换将非分区表转换为分区表
            干货攻略丨DM8并行查询


            最后修改时间:2021-01-29 16:36:42
            文章转载自达梦大学,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论