事务(进程ID)在锁资源上与另一个进程死锁,并被选为死锁牺牲品.重新运行该交易

use*_*213 18 c# sql-server multithreading deadlock

我有一个C#应用程序,它使用存储过程将数据插入SQL Server(2008)表.我正在使用多线程来做到这一点.正在从线程内部调用存储过程.现在我的存储过程在插入数据时使用"tablock".执行此代码时,我收到以下错误:"事务(进程ID)已锁定资源与另一个进程死锁,并已被选为死锁牺牲品.重新运行该事务."

任何人都可以帮我解决这个问题吗?

Ben*_*Ben 15

当两个Sql Server进程访问相同的资源但以不同的顺序访问时,会发生这种情况.因此他们最终都在等待另一个进程,这是一个僵局.

有许多方法可以防止它,包括:

  • 避免不必要的锁定.查看查询所需的事务隔离级别,with (nolock)在适当的地方使用锁定提示查询.
  • 确保在获取锁定时,您可以在每个查询中以相同的顺序对对象进行锁定.

例如,如果Proc1锁定table1然后锁定table2,但Proc2锁定table2然后锁定table1,则可能会出现问题.您可以重写任一proc以相同顺序获取锁以避免此问题.


Mez*_*Mez 6

您可以将查询封装在TRY CATCH块中,并捕获错误号(与锁有关)

  1. 1204
  2. 1205
  3. 1222

然后,您可以自动重试(最多重试一次)。因此,您将执行以下操作:

         DECLARE @RetryNo Int = 1
     ,@RetryMaxNo Int = 5;
   WHILE @RetryNo < @RetryMaxNo
      BEGIN
         BEGIN TRY 

         -- put your query that generates locks here....

            SELECT   @RetryNo = @RetryMaxNo;
         END TRY
         BEGIN CATCH
            IF ERROR_NUMBER() IN (1204, 1205, 1222)
               BEGIN
                  SET @RetryNo += 1;
                  -- it will wait for 10 seconds to do another attempt
                  WAITFOR DELAY '00:00:10';
               END 
            ELSE
               THROW;
         END CATCH
      END 
Run Code Online (Sandbox Code Playgroud)

您还可以使用表提示,例如UPDLOCK

  • 重试`SqlConnectionBroken = -1,SqlTimeout = -2,SqlOutOfMemory = 701,SqlOutOfLocks = 1204,SqlDeadlockVictim = 1205,SqlLockRequestTimeout = 1222,SqlTimeoutWaitingForMemoryResource = 8645,SqlLowMemoryCondition = 8651,Sq lWordbreakerTimeout = 30053` (3认同)

归档时间:

查看次数:

50359 次

最近记录:

6 年,8 月 前