我遇到以下存储过程的间歇性死锁。它每分钟运行一次。它已经投入生产 1 年多,我们通常不会收到此错误,但有时会突然出现......它在我们的一个环境中每天抛出 3 到 5 次异常......它与其他实例的环境相同没有抛出错误。存储过程是这样创建的,所以它一次只能运行一次,但也许我们这样做的方式不正确?
这是错误:
System.Web.HttpUnhandledException:引发了“System.Web.HttpUnhandledException”类型的异常。---> System.Data.SqlClient.SqlException:事务(进程 ID 60)在锁定资源上与另一个进程死锁,并已被选为死锁受害者。重新运行事务。
这是存储过程:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[requestUpdate]
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRAN
DECLARE @StartDate datetime,
@EndDate datetime,
@Throttle bit,
@Expired bit
SELECT @Throttle = 0
SELECT @Expired = 0
SELECT TOP 1 @StartDate = uq.StartDate, @EndDate = uq.EndDate
FROM UpdateQueue uq WITH(TABLOCK,XLOCK)
ORDER BY ID DESC
-- PREVENT ANOTHER REQUEST IF THIS SP HAS BEEN
-- CALLED IN THE LAST FORTY SECONDS.
IF DATEADD(SECOND,-40,GETDATE()) < @StartDate
BEGIN
SELECT @Throttle = 1
END
-- CREATE ANOTHER REQUEST IF THE CURRENT ONE
-- HAS NOT COMPLETED IN THE LAST FIVE MINUTES.
IF @StartDate <= DATEADD(MINUTE,-5,GETDATE())
BEGIN
SELECT @Expired = 1
END
-- HAS THE CURRENT REQUEST EXPIRED?
IF @EndDate IS NULL AND @Expired = 1
BEGIN
INSERT INTO UpdateQueue (RequestID, StartDate) OUTPUT 'EXPIRED' AS Result, INSERTED.RequestID AS RequestID
VALUES (NEWID(), GETDATE())
END
-- HAS THE CURRENT REQUEST COMPLETED AND YOU ARE NOT THROTTLING
-- OR HAVE THERE NOT BEEN ANY REQUESTS YET?
ELSE IF (@EndDate IS NOT NULL AND @Throttle = 0) OR @StartDate IS NULL
BEGIN
INSERT INTO UpdateQueue (RequestID, StartDate) OUTPUT 'STARTED' AS Result, INSERTED.RequestID AS RequestID
VALUES (NEWID(), GETDATE())
END
-- Running
ELSE
BEGIN
SELECT 'RUNNING' AS Result, NULL AS RequestID
END
COMMIT