【问题标题】:How to prevent deadlock in SQL Server stored procedure?如何防止 SQL Server 存储过程中的死锁?
【发布时间】:2017-05-22 16:25:39
【问题描述】:

我正在调用一个存储过程,该过程执行INSERTUPDATE,具体取决于表中存在的过程键。

到目前为止,程序按预期工作。直到我们的用户群开始扩大。今天我收到以下错误,通过重新启动运行该服务的应用程序池解决了这个错误:

InsertDDM_UserDashboard 错误:RequestError:事务(进程 ID 64)在锁资源上与另一个进程死锁,并已被选为死锁牺牲品。重新运行事务。

如何防止 SQL Server 存储过程中的死锁?

我查看了this link,这表明SELECTUPDATE 同时运行可能导致死锁。但我的程序用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

【问题讨论】:

    标签: sql-server stored-procedures transactions deadlock


    【解决方案1】:

    您可以像这样使用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
    

    【讨论】:

      【解决方案2】:

      需要查看表和索引 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多