如何防止 SQL 服务器存储过程中的死锁?
How to prevent deadlock in SQL Server stored procedure?
我正在调用一个存储过程,该过程执行 INSERT
或 UPDATE
取决于 table 中存在的过程键。
到目前为止,程序按预期运行。直到我们的用户群开始扩大。今天我收到以下错误,通过重新启动应用程序池 运行 服务解决了该错误:
InsertDDM_UserDashboard error: RequestError: Transaction (Process ID 64) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
如何防止 SQL 服务器存储过程中的死锁?
我查看了 this link,这表明它可能是 SELECT
和 UPDATE
运行ning 同时导致死锁的问题。但是我的程序用 IF..ELSE
条件将语句分开,因此两者不能同时 运行。
存储过程:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[InsertDDM_UserDashboard]
@p_email VARCHAR(255),
@p_dashboardPreferences VARCHAR(4000),
@p_userDefaultDashboard VARCHAR(500)
AS
IF (NOT EXISTS(SELECT * FROM [dbo].[DDM_UserProfile] WHERE Email = @p_email))
BEGIN
INSERT INTO [dbo].[DDM_UserProfile]
([Email]
,[DashboardPreferences]
,DefaultDashboard
)
VALUES
(@p_email
,@p_dashboardPreferences
,@p_userDefaultDashboard
)
END ELSE BEGIN
UPDATE [dbo].[DDM_UserProfile]
SET [DashboardPreferences]=@p_dashboardPreferences
WHERE [Email]=@p_email
UPDATE [dbo].[DDM_UserProfile]
SET DefaultDashboard=@p_userDefaultDashboard
WHERE [Email]=@p_email
END
需要查看 table 和索引 DDL 以及完整的死锁图才能确定,但您可能只需要在初始读取时锁定目标行。 EG
ALTER PROCEDURE [dbo].[InsertDDM_UserDashboard]
@p_email VARCHAR(255),
@p_dashboardPreferences VARCHAR(4000),
@p_userDefaultDashboard VARCHAR(500)
AS
begin
begin transaction
IF (NOT EXISTS(SELECT * FROM [dbo].[DDM_UserProfile] with (updlock, holdlock) WHERE Email = @p_email))
BEGIN
INSERT INTO [dbo].[DDM_UserProfile]
([Email]
,[DashboardPreferences]
,DefaultDashboard
)
VALUES
(@p_email
,@p_dashboardPreferences
,@p_userDefaultDashboard
)
END
ELSE
BEGIN
UPDATE [dbo].[DDM_UserProfile]
SET [DashboardPreferences]=@p_dashboardPreferences,
DefaultDashboard=@p_userDefaultDashboard
WHERE [Email]=@p_email
END
commit transaction
end
您可以像这样使用 Sam Saffron upsert approach:
create procedure dbo.ddm_UserProfile_Dashboard_upsert (
@p_email varchar(255)
, @p_dashboardPreferences varchar(4000)
, @p_userDefaultDashboard varchar(500)
) as
begin
set nocount, xact_abort on;
begin tran;
update up
set DashboardPreferences=@p_dashboardPreferences
, DefaultDashboard =@p_userDefaultDashboard
from dbo.ddm_UserProfile up with (serializable)
where up.Email = @p_email;
if @@rowcount = 0
begin;
insert into dbo.ddm_UserProfile (Email, DashboardPreferences, DefaultDashboard)
values (@p_email, @p_dashboardPreferences, @p_userDefaultDashboard);
end;
commit tran;
end;
go
我正在调用一个存储过程,该过程执行 INSERT
或 UPDATE
取决于 table 中存在的过程键。
到目前为止,程序按预期运行。直到我们的用户群开始扩大。今天我收到以下错误,通过重新启动应用程序池 运行 服务解决了该错误:
InsertDDM_UserDashboard error: RequestError: Transaction (Process ID 64) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
如何防止 SQL 服务器存储过程中的死锁?
我查看了 this link,这表明它可能是 SELECT
和 UPDATE
运行ning 同时导致死锁的问题。但是我的程序用 IF..ELSE
条件将语句分开,因此两者不能同时 运行。
存储过程:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[InsertDDM_UserDashboard]
@p_email VARCHAR(255),
@p_dashboardPreferences VARCHAR(4000),
@p_userDefaultDashboard VARCHAR(500)
AS
IF (NOT EXISTS(SELECT * FROM [dbo].[DDM_UserProfile] WHERE Email = @p_email))
BEGIN
INSERT INTO [dbo].[DDM_UserProfile]
([Email]
,[DashboardPreferences]
,DefaultDashboard
)
VALUES
(@p_email
,@p_dashboardPreferences
,@p_userDefaultDashboard
)
END ELSE BEGIN
UPDATE [dbo].[DDM_UserProfile]
SET [DashboardPreferences]=@p_dashboardPreferences
WHERE [Email]=@p_email
UPDATE [dbo].[DDM_UserProfile]
SET DefaultDashboard=@p_userDefaultDashboard
WHERE [Email]=@p_email
END
需要查看 table 和索引 DDL 以及完整的死锁图才能确定,但您可能只需要在初始读取时锁定目标行。 EG
ALTER PROCEDURE [dbo].[InsertDDM_UserDashboard]
@p_email VARCHAR(255),
@p_dashboardPreferences VARCHAR(4000),
@p_userDefaultDashboard VARCHAR(500)
AS
begin
begin transaction
IF (NOT EXISTS(SELECT * FROM [dbo].[DDM_UserProfile] with (updlock, holdlock) WHERE Email = @p_email))
BEGIN
INSERT INTO [dbo].[DDM_UserProfile]
([Email]
,[DashboardPreferences]
,DefaultDashboard
)
VALUES
(@p_email
,@p_dashboardPreferences
,@p_userDefaultDashboard
)
END
ELSE
BEGIN
UPDATE [dbo].[DDM_UserProfile]
SET [DashboardPreferences]=@p_dashboardPreferences,
DefaultDashboard=@p_userDefaultDashboard
WHERE [Email]=@p_email
END
commit transaction
end
您可以像这样使用 Sam Saffron upsert approach:
create procedure dbo.ddm_UserProfile_Dashboard_upsert (
@p_email varchar(255)
, @p_dashboardPreferences varchar(4000)
, @p_userDefaultDashboard varchar(500)
) as
begin
set nocount, xact_abort on;
begin tran;
update up
set DashboardPreferences=@p_dashboardPreferences
, DefaultDashboard =@p_userDefaultDashboard
from dbo.ddm_UserProfile up with (serializable)
where up.Email = @p_email;
if @@rowcount = 0
begin;
insert into dbo.ddm_UserProfile (Email, DashboardPreferences, DefaultDashboard)
values (@p_email, @p_dashboardPreferences, @p_userDefaultDashboard);
end;
commit tran;
end;
go