我正在使用SQL Server 2008 Enterprise。我想知道死锁问题是否只是由交叉依赖引起的(例如,任务A锁定了L1,但在L2上等待锁定,同时,任务B锁定了L2,但等待锁定在L1上)?是否有其他原因和情况会导致死锁?
是否还有其他导致死锁的方法 - 例如超时(S / I / D / U语句很长时间没有返回,并且会返回死锁错误)或者无法长时间获取锁定但不是由交叉依赖性引起的(例如任务C需要获取)锁定表T,但另一个任务D获取表T上的锁而不释放锁,这导致任务C无法长时间锁定表T?)
编辑1:如果多个线程同时执行此存储过程会导致死锁吗?
create PROCEDURE [dbo].[FooProc]
(
@Param1 int
,@Param2 int
,@Param3 int
)
AS
DELETE FooTable WHERE Param1 = @Param1
INSERT INTO FooTable
(
Param1
,Param2
,Param3
)
VALUES
(
@Param1
,@Param2
,@Param3
)
DECLARE @ID bigint
SET @ID = ISNULL(@@Identity,-1)
IF @ID > 0
BEGIN
SELECT IdentityStr FROM FooTable WHERE ID = @ID
END
提前谢谢,
乔治
答案 0 :(得分:2)
死锁需要一个循环,其中资源被等待其他进程持有的锁以释放锁的进程锁定。任何数量的进程都可以参与死锁,检测死锁的常规方法是获取锁的依赖关系图并搜索该图中的循环。
你需要让这个循环存在死锁。其他任何事情只是一个等待锁定被释放的过程。 sp_who2是一种快速查看其他进程被阻止的进程的方法。
如果要对死锁进行故障排除,最好的方法是运行跟踪,获取“死锁图”事件。这将允许您通过告诉您哪些查询持有锁来查看正在发生的事情。
答案 1 :(得分:2)
还有转换死锁:进程A和B都在资源C上有共享锁。两者都希望在C上获得独占锁。
即使两个进程只在一个资源上竞争,它们仍然可以陷入僵局。以下脚本重现了这种情况。在一个选项卡中,运行:
CREATE TABLE dbo.Test ( i INT ) ;
GO
INSERT INTO dbo.Test
( i )
VALUES ( 1 ) ;
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
BEGIN TRAN
SELECT i
FROM dbo.Test ;
--UPDATE dbo.Test SET i=2 ;
此脚本完成后,我们有一个持有共享锁的未完成事务。在另一个选项卡中,让我们让另一个连接在同一资源上具有共享锁:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
BEGIN TRAN
SELECT i
FROM dbo.Test ;
--UPDATE dbo.Test SET i=2 ;
此脚本完成并呈现结果集,就像第一个脚本一样。现在让我们在两个选项卡中突出显示并执行注释的更新命令。要执行更新,每个连接都需要一个独占锁。两个连接都不能获得该独占锁,因为另一个连接是持有共享锁。虽然两个连接只在一个资源上竞争,但它们已经接受了转换死锁:
Msg 1205,Level 13,State 56,Line 1 事务(进程ID 59)在锁资源上与另一个进程发生死锁,并被选为死锁牺牲品。重新运行该交易。
另请注意,死锁可能包含两个以上的连接。
答案 2 :(得分:0)
长时间不释放锁定并不是一个僵局。
僵局是一种永远无法前进的局面。它是由等待其他人完成的2个(或更多)进程引起的,但所有涉及的进程都持有阻止其他进程继续的锁。
解决死锁的唯一方法就是杀死进程以释放锁,因为无论你等待多久都无关紧要,它无法自行完成。