阻塞
在程序运行时,如果有异常长时间执行等待无结果,可以排查是否有阻塞的情况。在 DM 数据库中, INSERT、 UPDATE、 DELETE 是最常见的会产生阻塞和死锁的语句。INSERT 发生阻塞的唯一情况是, 当多个事务同时试图向有主键或 UNIQUE 约束的表中插入相同的数据时,其中的一个事务将被阻塞,直到另外一个事务提交或回滚。一个事务提交时,另一个事务将收到唯一性冲突的错误;一个事务回滚时,被阻塞的事物可以继续执行。当 UPDATE 和 DELETE 修改的记录,已经被另外的事务修改过, 将会发生阻塞,直到另一个事务提交或回滚。dm8中可以使用下面的sql语句查询阻塞信息
WITH TRX_TAB AS
(SELECT DISTINCT O1.NAME,L1.TRX_ID FROM V$LOCK L1,SYSOBJECTS O1 WHERE L1.TABLE_ID=O1.ID AND O1.ID<>0),
TRX_SESS AS (
SELECT L.TRX_ID WT_TRXID, L.ROW_IDX BLK_TRXID,L.BLOCKED,(SELECT NAME TABLE_NAME FROM TRX_TAB A WHERE A.TRX_ID=L.TRX_ID) WT_TABLE,
S1.SESS_ID WT_SESS,S2.SESS_ID BLK_SESS,
S1.USER_NAME WT_USER_NAME,S2.USER_NAME BLK_USER_NAME,S1.SQL_TEXT,S1.CLNT_IP,DATEDIFF(SS, S1.LAST_SEND_TIME, SYSDATE) SS
FROM V$LOCK L,V$SESSIONS S1,V$SESSIONS S2
WHERE L.TRX_ID=S1.TRX_ID AND L.ROW_IDX=S2.TRX_ID)
SELECT SYSDATE STATTIME,* FROM TRX_SESS where BLOCKED=1;
插入测试
新建一张测试表,字段id为主键
create table person (id int primary key,name varchar(20));
插入两次记录,其中id字段相同
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZZhp3Yp-1690706426215)(C:\Users\yankai2000\AppData\Roaming\Typora\typora-user-images\image-20230615100255033.png)]](/https://i-blog.csdnimg.cn/blog_migrate/f2e90eaa5c366d61ac4468773aa2da60.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9tFDNdT-1690706426216)(C:\Users\yankai2000\AppData\Roaming\Typora\typora-user-images\image-20230615100327077.png)]](/https://i-blog.csdnimg.cn/blog_migrate/2b37c6c9d9a10d12c67a36ccc2eafd49.png)
可以看到第二次插入的记录已经阻塞
当阻塞发生时,我们可以通过 v$lock 视图查到当前数据库中锁的状态
select * from v$lock;
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKSiDTkv-1690706501986)(C:\Users\yankai2000\AppData\Roaming\Typora\typora-user-images\image-20230615100859924.png)]](/https://i-blog.csdnimg.cn/blog_migrate/be1d99768ba5774247cd43ace2e0db4a.png)
同样我们也可以通过 V$TRXWAIT 视图排查阻塞,
select * from v$trxwait;

结果中我们可以看到,事务 50140 被阻塞了,阻塞他的事务为 50136,
接下来,通过 V$SESSIONS 视图查找两个事务对应的会话,可以知道是哪些 SQL 语句产生的阻塞
select sess_id,sql_text,state,trx_id from v$sessions where trx_id in('50140','50136');,

阻塞和死锁本质上是多个事务同时并发对同一个对象进行访问、修改,先来的事务进行修改后没有即时释放锁资源导致后来的事务一直在等待,甚至在多个会话中两个以上的事务互相等待锁资源的释放导致的死锁现象,这种情况可以手动干预。
通过上诉分析方法找出相应的会话和事务,执行提交或回滚造成阻塞的事务,锁资源释放,sql顺利执行,也可以手动结束会话;通过查询v$trxwait视图,找出阻塞的事务ID,查询v$sessions视图,根据事务ID找出造成阻塞的会话,以本次模拟的阻塞为例,事务50136造成了阻塞,结束该会话;
sp_close_session(1828368696);

这样第二条记录就插入成功了
更新测试
事务一更新person表

事务二更新同一记录,可以看到事务二阻塞

问题:如果两次更新同一记录的不同字段是否会阻塞?
回答:是的,因为事务一已经持有了行级锁,事务二无法拿到,阻塞
问题:如果第二次更新的是范围记录是否会阻塞?
回答:只要这次范围更新包含了第一次更新的记录就会阻塞
死锁
第一个事务执行
update person set name='c' where id =1;
第二个事务执行
update person set name='dd' where id =2;
第一个事务执行
update person set name='d' where id =2;
第二个事务执行
update person set name='cc' where id =1;
发生了死锁

死锁与阻塞的不同之处在于死锁包括两个或者多个已阻塞事务,它们之间形成了等待环,每个都等待其他事务释放锁。例如事务1给表T1上了排他锁,第二个事务给表T2上了排他锁,此时事务1请求T2的排他锁,就会处于等待状态,被阻塞。若此时T2再请求表T1的排他锁,则T2也处于阻塞状态。此时这两个事务发生死锁,DM数据库会选择牺牲掉其中一个事务。
死锁的本质也是锁等待,所以解决锁等待的问题,就解决了死锁的问题。
查询阻塞事务
sql> select * from V$TRXWAIT ;
ID WAIT_FOR_ID WAIT_TIME THRD_ID
50348 50352 110578 4120
查询会话
sql> SELECT SESS_ID,SQL_TEXT,TRX_ID,THRD_ID from V$SESSIONS where TRX_ID=50352;
SESS_ID SQL_TEXT TRX_ID THRD_ID
1830502712 update person set name='cc' where id =1; 50352 4120
关闭会话
SP_CLOSE_SESSION(1830502712);
本文详细介绍了DM数据库中阻塞和死锁的现象、原因以及处理方法。通过示例展示了插入和更新操作可能导致的阻塞,并提供查询视图来定位和解决阻塞问题。对于死锁,解释了其形成的原因并给出了解决死锁的策略,强调解决锁等待即可避免死锁。

6736

被折叠的 条评论
为什么被折叠?



