达梦数据库阻塞/死锁模拟

1. 背景

在项目实际运行中,可能由于程序逻辑冲突或者人为操作 导致多个会话同时对一张表的同一条数据进行修改( 即第一个连接占有资源没有释放,而第二个连接需要获取这个资源),如果第一个连接没有提交或者回滚,第二个连接会一直等待下去,这就产生了阻塞。对于阻塞,数据库无法处理,所以对数据库操作要及时地提交或者回滚;


另一种情况:第一个连接占有资源没有释放,准备获取第二个连接所占用的资源,而第二个连接占有资源没有释放,

准备获取第一个连接所占用的资源。 这种互相占有对方需要获取的资源的现象叫做死锁。

对于死锁,数据库处理方法:牺牲一个连接,保证另外一个连接成功执行。

2. 目标

通过本地模拟阻塞和死锁场景,查询动态视图,能够快速定位阻塞问题。

 

 

3. 模拟阻塞场景

3.1     创建测试表和数据

 

       create table t1_deadlock ( a int );

       create table t2_deadlock ( a int );

 

       insert into t1_deadlock values ( 1 );

       insert into t2_deadlock values ( 2 );

       commit ;

 

 

3.2 创建阻塞事务

会话1执行:修改t1表,不提交

 

 

 

 

会话2执行,修改t2表,不提交

         

 

 

 

回到会话1,修改t2表,不提交,

此时产生阻塞

          

 


来到会话2,修改t1表:

此时产生死锁

         


 

注意:达梦在出现死锁后,会自动kill掉死锁的会话(这里是会话2),然后会话1仍处于阻塞状态,需要手动提交或回滚。

 

4.相关视图查询

此时即产生了阻塞,查询 v$trx可以看到相关信息:

select status,ID,sess_id from v$trx where status = 'LOCK WAIT';


 

 

 

 

将 sess_id 放到会话视图中查,可以找被阻塞的SQL:

 



 

同时,查询v$lock可以看到与锁有关的信息:

select o.name,l.* from v$lock l,sysobjects o where l.table_id=o.id and blocked=1;


 


 

其中 TRX_ID,TID 都对应的是v$sessions中的TRX_ID:

 

 


下面是排查阻塞常用的SQL语句:


--查询阻塞源头

  select sf_get_session_sql(sess_id)as 阻塞源SQL,

  datediff(ss,last_recv_time,sysdate) as "阻塞持续时长(秒)",

  TRX_ID,*

  from v$sessions where trx_id in (select wait_for_id from v$trxwait where wait_for_id not in (select id from v$trxwait));

 


--查询所有被阻塞的语句

 select a.id as trx_id,a.sess_id,a.status 事务状态,b.sql_text,a.waiting 事务等待的锁, 

 b.CLNT_IP 客户端IP,b.state 会话状态

 from  v$trx a 

 left join v$sessions b on a.sess_id = b.sess_id

 where a.status = 'LOCK WAIT' ;

 

 



请使用浏览器的分享功能分享到微信等