数据库死锁 之 一.啥是死锁

数据库死锁 之 啥是死锁

 

1.理解死锁

  -- 1.1 学习资料  https://www.cnblogs.com/firstdream/p/4624473.html

    资源的死锁是因为资源的多方,自己需要使用的资源被其他人占用上锁;导致互相等待;从而发生死锁;
    先理解下锁概念,数据库存在 X 锁 & S 锁;
 
锁类型
特性
说明
场景
X
排他独占
 
1.一旦上锁无法上其他锁
1.update 场景会上锁
2.delete 场景会上锁
S
共享
 
1.可与其他的共享锁功能存在
2.当存在X锁,无法上S锁,因为X排他
1.select 场景
 

   -- 1.2 死锁场景

       -- 1.2.1 死锁场景一,多表交叉死锁
        A.先创建表TestA,TestB
CREATE TABLE TestA
(
  Name NVARCHAR(100)
)
CREATE TABLE TestB
(
  Name NVARCHAR(100)
)

      B.触发死锁,让我们玩坏这个

CREATE PROC p_TestA
as
BEGIN TRANSACTION ;
INSERT INTO TestA(Name) VALUES('张三') ;
SELECT name FROM TestB;
COMMIT;
CREATE PROC p_TestB
as
BEGIN TRANSACTION ;
INSERT INTO TestB(Name) VALUES('张三') ;
SELECT name FROM TestA;
COMMIT;
    C.写两个现程循环调用这两个存储过程
using (SqlConnection conn = new SqlConnection("XXX"))
{
    SqlCommand commmand = new SqlCommand();
    commmand.Connection = conn;
    commmand.CommandText = "exec p_TestA;";
    conn.Open();
    commmand.ExecuteNonQuery();
    conn.Close();
    commmand.Dispose();
    conn.Dispose();
}
    :)    # 看到没,终于玩坏了
 
 
    -- 1.2.2 死锁场景二 单表死锁
前面所说到,是资源互相的占用上锁导致死锁,那单表怎么死锁呢?
语句1:select A,B,C from TestA where id in ('');
语句2:delete TestA where id in (''); 
这里说明下字段的索引情况;存在主键id 是聚集索引,A,B是非聚集索引;
这种场景下,如果高并发的发生语句1和2就会发生死锁。why?来,我们一步步分析
语句一:首先查询A,B,因为存在索引,所以在索引 A,B上加上了S锁,也就是共享查询锁;然后下一步呢?C字段比较特殊了,没有索引,所以就需要使用一个新概念了,bookmark search ,也就是书签查;这里C列会通过聚集索引(物理索引)来查找,所以会给聚集索引加上S锁;
缕一缕
第一步:给 A,B 上S锁
第二部:给 id 上S锁
语句二:删除表数据,
第一步:首先给id聚集索引上X锁(排他锁);
第二步:数据更新后,要求更新其他索引,索引需要给A,B索引上X锁;
那么结论就出来了,这两个步骤中出现了互相占用资源的场景,所以死锁了。。。
这种死锁其实只要在字段C加上索引就可以解决,保证查询中不在依赖主键做书签查找即可,所以请关注你的select,不要的列不要乱加哦;
原文地址:https://www.cnblogs.com/tiaoshuidenong/p/13594430.html