DM8锁等待和死锁

Posted yangeoooo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DM8锁等待和死锁相关的知识,希望对你有一定的参考价值。

DM事务锁

创建测试表

create table t_test01(id int primary key, name varchar(20));
select * from t_test01;
select name,id from sysobjects where name='T_TEST01';
LINEID     NAME     ID         
---------- -------- -----------
1          T_TEST01 1486
select trx_id,ltype,lmode,blocked,table_id,tid from v$lock where table_id=1486;

LINEID     TRX_ID               LTYPE  LMODE BLOCKED     TABLE_ID    TID                 
---------- -------------------- ------ ----- ----------- ----------- --------------------
1          62313                OBJECT IS    0           1486        62313

新窗口插入数据

SQL> insert into t_test01(id, name) values(1, 'cheng');
affect rows 1

再次查询lock表

select trx_id,ltype,lmode,blocked,table_id,tid from v$lock where table_id=1486;
SQL> /

LINEID     TRX_ID               LTYPE  LMODE BLOCKED     TABLE_ID    TID                 
---------- -------------------- ------ ----- ----------- ----------- --------------------
1          62313                OBJECT IS    0           1486        62313
2          62314                OBJECT IS    0           1486        62314
3          62314                OBJECT IX    0           1486        62314

锁等待

场景一:INSERT锁等待

create table t_test01(id int primary key, name varchar(20));
select name,id from sysobjects where name='T_TEST01';

LINEID     NAME     ID         
---------- -------- -----------
1          T_TEST01 1487

开启两个新会话执行,第二个会话会等待

insert into t_test01(id, name) values(1, 'cheng');

查询锁 查询v$lock可以看到该对象新增了TID共享锁(S锁),并且该锁BLOCKED=1,该锁被62323

SQL>  select trx_id,ltype,lmode,blocked,table_id,tid from v$lock where table_id=1487;

LINEID     TRX_ID               LTYPE  LMODE BLOCKED     TABLE_ID    TID                 
---------- -------------------- ------ ----- ----------- ----------- --------------------
1          62323                OBJECT IS    0           1487        62323
2          62323                OBJECT IX    0           1487        62323
3          62324                OBJECT IX    0           1487        62324
4          62324                TID    S     1           1487        62323

提交第一个insert into后,可以看到提交之后相关的事务锁已经释放,并且会话二抛出异常:

1*  select trx_id,ltype,lmode,blocked,table_id,tid from v$lock where table_id=1487;
SQL> /

LINEID     TRX_ID               LTYPE  LMODE BLOCKED     TABLE_ID    TID                 
---------- -------------------- ------ ----- ----------- ----------- --------------------
1          0                    OBJECT IS    0           1487        62323
2          0                    OBJECT IX    0           1487        62323
3          62324                OBJECT IX    0           1487        62324

02 锁等待解决方法

但实际业务中,我们可能无法手工提交阻塞的会话,此时可以强制杀死会话:
使用如下语句查询处于等待的锁(或查询v$trxwait可以查看阻塞事务):

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

LINEID     TRX_ID               LTYPE LMODE BLOCKED     TABLE_ID    TID                 
---------- -------------------- ----- ----- ----------- ----------- --------------------
1          62324                TID   S     1           1487        62326
SQL> select * from v$trxwait;

LINEID     ID                   WAIT_FOR_ID          WAIT_TIME  
---------- -------------------- -------------------- -----------
1          62324                62326                74926

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

 select SESS_ID,SQL_TEXT,TRX_ID,THRD_ID from v$sessions where TRX_ID=62326;

LINEID     SESS_ID              SQL_TEXT                                           TRX_ID               THRD_ID    
---------- -------------------- -------------------------------------------------- -------------------- -----------
1          140159412672120      insert into t_test01(id, name) values(2, 'cheng'); 62326                43777

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

SQL> sp_close_session(140159412672120);
DMSQL executed successfully
select trx_id,ltype,lmode,blocked,table_id,tid from v$lock where table_id=1487;

LINEID     TRX_ID               LTYPE  LMODE BLOCKED     TABLE_ID    TID                 
---------- -------------------- ------ ----- ----------- ----------- --------------------
1          62324                OBJECT IX    0           1487        62324
2          62324                TID    S     0           1487        62326

死锁

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

create table t_test02(id int primary key, name varchar(20));

会话1
insert into t_test01(id, name) values(3,‘qing’);

会话2
insert into t_test02(id, name) values(3,‘qing’);

会话1
insert into t_test02(id, name) values(3,‘qing’);
会话2
insert into t_test01(id, name) values(3,‘qing’);
[-6403]:Deadlock.
used time: 238.724(ms). Execute id is 0.

死锁的本质也是锁等待,所以解决锁等待的问题,就解决了死锁的问题。

SQL> select * from v$trxwait;


LINEID     ID                   WAIT_FOR_ID          WAIT_TIME  
---------- -------------------- -------------------- -----------
1          62327                62324                194086


SQL> select SESS_ID,SQL_TEXT,TRX_ID,THRD_ID from v$sessions where TRX_ID=62324;

LINEID     SESS_ID              SQL_TEXT                                         TRX_ID               THRD_ID    
---------- -------------------- ------------------------------------------------ -------------------- -----------
1          96965128             insert into t_test01(id, name) values(3,'qing'); 62324                43530

used time: 4.119(ms). Execute id is 900.


sp_close_session(96965128);

DDL锁超时

当我们对某张表执行DDL操作时(比如修改某张表的表结构),若当前表上有排他锁(未提交的DML事务),此时数据库会根据锁的等待时间抛出锁超时的异常。
DM数据库的DDL锁超时时间是由参数DDL_WAIT_TIME指定,默认十秒,可根据实际需要修改。

SQL> select * from v$dm_ini t where t.PARA_NAME = 'DDL_WAIT_TIME';

LINEID     PARA_NAME     PARA_VALUE MIN_VALUE MAX_VALUE DEFAULT_VALUE MPP_CHK SESS_VALUE FILE_VALUE DESCRIPTION                              PARA_TYPE
---------- ------------- ---------- --------- --------- ------------- ------- ---------- ---------- ---------------------------------------- ---------
1          DDL_WAIT_TIME 10  

锁超时场景测试:
新增会话一,在T_TEST01表中插入数据(未提交),产生一个排他锁:
insert into t_test01(id, name) values(2, ‘qing’);
新增会话二,执行DDL语句(对t_test01新增字段),此时会话处理等待状态:
alter table t_test01 add column info1 varchar(50);

SQL> select trx_id,ltype,lmode,blocked,table_id,tid from v$lock where table_id=1487;

LINEID     TRX_ID               LTYPE  LMODE BLOCKED     TABLE_ID    TID                 
---------- -------------------- ------ ----- ----------- ----------- --------------------
1          62327                OBJECT IS    0           1487        62327
2          62327                OBJECT IX    0           1487        62327
3          62334                OBJECT IS    0           1487        62333
4          62334                OBJECT IX    0           1487        62333
5          62334                OBJECT X     1           1487        62334

大概十多秒,会话二抛出锁超时的异常:
锁超时的本质原因是锁等待,解决锁等待的问题,就解决了锁超时的问题。

以上是关于DM8锁等待和死锁的主要内容,如果未能解决你的问题,请参考以下文章

多线程死锁避免

oracle 死锁和锁等待的区别,锁等待

如何减少SQLServer死锁发生

数据库死锁怎么处理

事务(进程 ID 84)与另一个进程在锁资源上死锁,并已被选为死锁牺牲品

事务(进程 ID 120)与另一个进程在锁资源上死锁,并已被选为死锁牺牲品。重新运行事务