达梦数据库锁表解决方案[转]

1. 定义

阻塞:多个线程之间的相互影响,等待临界资源;
死锁:多个线程之间互相等待,形成等待环;

对于死锁,达梦数据库会自动检测,并选择牺牲掉其中的一个事务,保证其它事务正常运行。死锁一般是由于应用程序bug导致的,当有修改多表的事务时,应尽量保证每个事务以相同的顺序锁定表。可以通过V$DEADLOCK_HISTORY查询死锁历史,其中记录了产生死锁后被牺牲掉的事务的事务ID、会话ID、执行的SQL语句以及死锁发生时间(没有记录造成死锁的其它事务)。对于阻塞,达梦数据库不会自动处理,被阻塞的事务会一直挂起,直到获取到所需的资源。阻塞一般是由应用程序bug造成的,在应用编写中,应尽量形成短事务,快速提交。

2. 什么情况下会形成阻塞?
在达梦数据库中,默认采用读提交的机制,查询永远不会被阻塞。查询一般情况下也不会阻塞增删改操作,SELECT FOR UPDATE的情况除外。
INSERT语句被阻塞的情况:多个事务同时向有主键或唯一约束的表中插入相同的数据;
删、改语句被阻塞的情况:所需要操作的数据被其它事务修改过,且一直没有提交或回滚;

示例:
job表结构和数据如图

  

先执行:update "DMHR"."JOB" set MIN_SALARY='10000' where JOB_ID='73'

 


再执行:select * from "DMHR"."JOB" where JOB_ID='73'

 

可以看到, select 操作可以正常进行。但是由于之前的事务没有提交,所以查出来的结果还是旧的值。


再执行:delete from "DMHR"."JOB" where JOB_ID='73';

 

此时,发生阻塞,因为 delete 操作需要加锁,当前事务被挂起。

3.阻塞的排查

当阻塞发生时,我们可以通过 v$lock 视图查到当前数据库中锁的状态

select * from v$lock;

 


结果中我们可以看到,事务 1459 被阻塞了,阻塞他的事务为 1450,同样我们也可以通过 V$TRXWAIT 视图排查阻塞,

select * from v$trxwait;

 

得出同样的结果,等待时间是1814645 毫秒。
接下来,通过 V$SESSIONS 视图查找两个事务对应的会话,可以知道是哪些 SQL 语句产生的阻塞。

select sess_id,sql_text,state,trx_id from v$sessions where trx_id in('1459','1450');

  

4.阻塞的解决方法


根据需求,可以有两种解决方案。
4.1 提交或回滚产生阻塞的事务。
根据上文,我们可知产生阻塞的事务会话 ID 为 140702994469648。此时,我们只需要在该会话下提交或回滚事务,锁自然会被释放,阻塞解决。

4.2 关闭产生阻塞的会话
同样,我们也可以使用系统过程 SP_CLOSE_SESSION(SESS_ID)来关闭对应的会话

 

此时,锁被释放,delete 操作也可以顺利进行下去。

 

 

 

备注:可以用一条语句查看出被阻塞的操作和事务会话 ID(SESS_ID)

select a.*, b.NAME, c.SESS_ID from v$lock a
left join sysobjects b on b.ID=a.TABLE_ID
left join v$sessions c on a.TRX_ID=c.TRX_ID;

然后直接执行SP_CLOSE_SESSION(SESS_ID) 来关闭对应的会话

参考链接:

https://blog.csdn.net/fengxiaozhenjay/article/details/101707104

https://blog.csdn.net/baidu_39362177/article/details/115866161

posted @ 2022-07-29 10:14  SolidMango  阅读(4590)  评论(0编辑  收藏  举报