Transaction And Lock--唯一索引下INSERT导致的死锁

背景:

曾经的一位同事问我:"数据库只有并发INSERT 操作,会造成死锁么?",我没有太多思考地回答"不会",但真的不会吗?

测试:

--=================================

--创建测试表

CREATE TABLE TB3

(

    ID INT PRIMARY KEY

)

GO

--===================================

--新开回话1

BEGIN TRAN 

INSERT INTO TB3

SELECT 2

WAITFOR DELAY '0:0:10'

INSERT INTO TB3

SELECT 1

--===================================

--新开回话2

BEGIN TRAN 

INSERT INTO TB3

SELECT 1



WAITFOR DELAY '0:0:10'

INSERT INTO TB3

SELECT 2

在上面的两个回话中,由于主键(唯一约束)的限制,相同的key对应相同的lock Resource,导致需要等待对方所获取的lock Resource,从而引发死锁

而如果将主键修改为非唯一索引,则不会引发死锁,相同的key对应不相同的lock Resource,因此不会造成相互等待也不引发死锁。

--====================================================================

--华丽的PS

对于最常见的死锁场景:

事务1 获取表TB1上的资源,请求表TB2上的资源

事务2 获取表TB2上的资源,请求表TB1上的资源

很多开发人员都会有意识保证各个事务访问不同表的顺序,从而避免此类死锁的发生,但很少会考虑对相同表的访问顺序,尤其在输入值被参数化的情况,如在下面的情况下:

BEGIN TRAN

UPDATE TB1

SET C2=@P2

WHERE C1=@P1



UPDATE TB1

SET C2=@P3

WHERE C1=@P3

COMMIT

 

在考虑是否会引发死锁时,我们除了分析当前语句外,还得检查这些语句所涉及到的表相关对象:触发器+外键+索引,还需分析其他业务场景的潜在影响。

PS:很多我们自认为正确的小结论,洗洗(细细)分析下,根本就是错误,而这些西奥结论,可能造成很恶劣影响。

--========================================================

照例妹子镇贴

Transaction And Lock--唯一索引下INSERT导致的死锁

图片来源于一豆瓣友邻

你可能感兴趣的:(transaction)