从存储过程catch块处理死锁重试是一个好主意

sky*_*yde 10 sql database sql-server deadlock

从我的承诺来看,不可能完全阻止交易陷入僵局.

我希望从应用程序代码的角度来看,交易永远不会失败.所以我已经看到这个模式用于Microsoft SQL,我想知道这是一个好主意吗?


    DECLARE @retry  tinyint
    SET @retry  = 5
    WHILE @retry >0
    BEGIN
      BEGIN TRANSACTION
      BEGIN TRY
        // do transaction her
        COMMIT
        BREAK
      END TRY
      BEGIN CATCH
        ROLLBACK

        if (ERROR_NUMBER() = 1205 OR ERROR_NUMBER() = 1222)
        BEGIN
          SET @retry = @retry - 1
          IF @retry = 0
             RAISEERROR('Could not complete transaction',16,1);
          WAITFOR DELAY '00:00:00.05' -- Wait for 50 ms
          CONTINUE
        END
        ELSE
        BEGIN
          RAISEERROR('Non-deadlock condition encountered',16,1);
          BREAK;
        END
      END CATCH;
    END

Ode*_*ded 7

你所拥有的实现并不是一个好主意,因为它在没有发现实际错误的情况下盲目地重试.例如,如果错误是超时,则可能最终将连接占用超时量的5倍,而无需解决问题.

一种更好的方法是检测它是错误1205 - 死锁受害者并仅在这种情况下重试.

您可以使用:

IF ERROR_NUMBER() = 1205 
Run Code Online (Sandbox Code Playgroud)

请参阅文档ERROR_NUMBER().


gbn*_*gbn 6

可恢复错误的重试逻辑应该在客户端代码中.

对于死锁,MSDN声明要在那里做

如果在SQL中重试,那么最终可能会命中CommandTimeout.

还有其他错误,因此您可以编写通用处理程序