Skip to main content
 首页 » 编程设计

c#之我可以使用C#锁来防止Web应用程序中的SQL Server死锁吗

2024年01月22日27xiaohuochai

我正在使用C#在Visual Studio 2010中编写Web应用程序。该Web应用程序执行复杂的SQL Server 2008语句,如果一次同时调用同一.aspx页不止一次,则有时会导致死锁。提出的解决方案是使用SQL Server手段来防止这些死锁,但是我的问题是我不太了解它,对于C#来说不是这样,我知道得更好。

因此,我想知道,使用ASP.NET页中的锁(或C#或Windows中称为互斥锁的锁)而不是通过SQL Server进行锁定以防止这些死锁的缺点是什么?

PS。该SQL Server数据库仅由该Web应用程序使用。

编辑:以下是执行SQL语句的C#代码:

int iNumRows = 0; 
 
using (SqlConnection cn = new SqlConnection(strConnection)) 
{ 
    cn.Open(); 
 
    using (SqlCommand cmd = new SqlCommand(strSQL, cn)) 
    { 
        //Use C# lock here 
        iNumRows = Convert.ToInt32(cmd.ExecuteScalar()); 
        //Release C# lock here 
    } 
} 


这是一个SQL示例(实际上是由C#脚本动态组成的):

SET XACT_ABORT ON; 
BEGIN TRANSACTION; 
 
DELETE FROM [dbo].[t_Log_2]  
      WHERE [idtm]<'2011-03-12 08:41:57'; 
 
WITH ctx AS( 
     SELECT MIN([idtm]) AS mdIn,  
            MAX([odtm]) AS mdOut  
           FROM [dbo].[t_Log_2]  
          WHERE [type] = 0  
            AND [state] = 0  
            AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'  
            AND [odtm] >= '2013-03-11 06:33:32'  
            AND [idtm] <= '2013-03-11 06:43:12'  
           )  
INSERT INTO [dbo].[t_Log_2]  
([oid],[idtm],[odtm],[type],[state],[huid], 
 [cnm],[cmdl],[batt],[dvtp0],[dvtp1])  
SELECT  
    2,  
    CASE WHEN mdIn IS NOT NULL  
          AND mdIn < '2013-03-11 06:33:32'  
         THEN mdIn  
         ELSE '2013-03-11 06:33:32'  
         END, 
    CASE WHEN mdOut IS NOT NULL  
          AND mdOut > '2013-03-11 06:43:12'  
         THEN mdOut  
         ELSE '2013-03-11 06:43:12'  
         END, 
    0, 
    0, 
    N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4', 
    null, 
    null, 
    0, 
    1, 
    null  
FROM ctx  
 
SELECT ROWCOUNT_BIG() 
 
DELETE FROM [dbo].[t_Log_2]  
      WHERE [type] = 0  
        AND [state] = 0  
        AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'  
        AND [odtm] >= '2013-03-11 06:33:32'  
        AND [idtm] <= '2013-03-11 06:43:12'  
        AND [id] <> SCOPE_IDENTITY() 
 
DELETE FROM [dbo].[t_Log_2]  
      WHERE [type] = 0  
        AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'  
        AND [idtm] >= (SELECT [idtm] FROM [dbo].[t_Log_2]  
                                    WHERE [id] = SCOPE_IDENTITY())  
        AND [odtm] <= (SELECT [odtm] FROM [dbo].[t_Log_2]  
                                    WHERE [id] = SCOPE_IDENTITY())  
        AND [id] <> SCOPE_IDENTITY()  
 
;WITH ctx1 AS(  
     SELECT [idtm] AS dI  
       FROM [dbo].[t_Log_2]  
      WHERE [id] = SCOPE_IDENTITY()  
             ) 
UPDATE [dbo].[t_Log_2]  
        SET [odtm] = ctx1.dI  
       FROM ctx1  
      WHERE [id] <> SCOPE_IDENTITY()  
        AND [type] = 0  
        AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'  
        AND [idtm] < ctx1.dI  
        AND [odtm] > ctx1.dI  
 
;WITH ctx2 AS( 
     SELECT [odtm] AS dO  
       FROM [dbo].[t_Log_2]  
      WHERE [id] = SCOPE_IDENTITY()  
             )  
UPDATE [dbo].[t_Log_2]  
        SET [idtm] = ctx2.dO  
       FROM ctx2  
      WHERE [id] <> SCOPE_IDENTITY()  
        AND [type] = 0  
        AND [huid] = N'18ef4d56-6ef3-906a-a711-88d1bd6ab2d4'  
        AND [idtm] < ctx2.dO  
        AND [odtm] > ctx2.dO  
 
COMMIT TRANSACTION; 
SET XACT_ABORT OFF 

请您参考如下方法:

使用ASP.NET页中的锁(或C#或Windows中名为互斥锁的锁)而不是通过SQL Server进行锁定以防止这些死锁的缺点是什么?


不会造成死锁,而是会导致死锁。

当等待图包含一个循环(A在B上等待,B在A上等待)时,将发生死锁。 SQL Server定期检查所有等待图并查找周期。当检测到一个这样的周期时,通过选择受害者并中止其交易来中断该周期。

如果将其中一些锁移出SQL Server控制的领域,即。在进程互斥体,关键部分,C#事件或任何其他情况下,仍将发生等待图循环,但现在该循环将通过应用程序完成,因此SQL Server无法检测到(A在SQL中等待B,但B等待A在应用中)。由于死锁监视器将看不到周期,因此它将不会运行死锁解析算法(选择受害者,中止其事务),并且死锁将永远保持下去。恭喜,现在您的应用程序只是挂起,而不引发死锁异常!

您不必信服我的话,这个问题已经使其他经验丰富的人烦恼了,并且学到了艰辛的方法,但是幸运的是写了它,以便您可以学习简单的方法。 This very site you're reading is an example。

了解问题后,解决SQL Server中的死锁就相当容易了。如果您capture and attach the deadlock graph(XML,而不是图片!)以及表的确切定义,也许我们可以为您提供帮助。 <,you already ignored such request,所以我想唯一要问的问题是,您还想要更多绳子吗?