在使用UPDLOCK,HOLDLOCK的表上运行存储过程时避免死锁

时间:2016-08-31 07:58:18

标签: sql-server tsql stored-procedures concurrency database-concurrency

我维护的存储过程将在用户访问网页时执行。

-- Existing tables
CREATE TABLE SourceAccount   
(
    Id bigint NOT NULL, 
    Value varchar(50) NOT NULL, 
    UpdateTime datetime2 NULL
)

CREATE TABLE TargetAccount 
(
    Id bigint NOT NULL, 
    Value varchar(50) NOT NULL, 
    UpdateTime datetime2 NULL
)

CREATE TABLE UpdatedCustomers
(
     CustomerID bigint NOT NULL, 
     SyncTime datetime2 NOT NULL
)

存储过程:

CREATE PROCEDURE TriggerAccountSync (
    @CustId bigint,      
    @LastUpdate DATETIME2)
AS 
BEGIN
    --if customer is outdated
    IF EXISTS(SELECT 1 FROM UpdatedCustomers 
              WHERE CustomerID = @CustId AND SyncTime < @LastUpdate)
    BEGIN
      BEGIN TRY
          INSERT INTO TargetAccount(Id, Value)
              SELECT Id, Value 
              FROM SourceAccount 
              LEFT OUTER JOIN TargetAccount WITH (UPDLOCK, HOLDLOCK) ON TargetAccount.Id = SourceAccount.Id 
              WHERE SourceAccount.UpdateTime IS NULL

          DELETE FROM TargetAccount 
          FROM SourceAccount 
          INNER JOIN TargetAccount WITH (UPDLOCK) ON TargetAccount.Id = SourceAccount.Id 
          WHERE TargetAccount.UpdateTime < @TimeStamp

          UPDATE UpdatedCustomers 
          SET SyncTime = @LastUpdate 
          WHERE CustomerID = @CustId            
      END TRY
      BEGIN CATCH
        --there are multiple simultaneous calls, it can fail with deadlock
        --don't raise error
      END CATCH
    END
END

我可以使用TRY CATCH THROW END CATCH抛出异常并仍然避免TargetAccount表上的死锁吗?我需要知道它何时无法同步。

如果存储过程无法完成,是否有办法释放表锁?

1 个答案:

答案 0 :(得分:2)

表锁是事务范围的。如果只有与存储过程关联的隐式事务,则只要存储过程结束,锁定也会一直存在,无论是否有任何错误。

在处理这样的锁时,使用显式事务通常很有用,这样您就可以更好地控制锁的生命周期,并使其在代码中更加明确(这样在事务处理时就不会产生混淆)嵌套的)。