c00*_*0fd 1 c# sql-server asp.net locking sql-server-2008
我正在使用C#在Visual Studio 2010中编写Web应用程序.Web应用程序执行复杂的SQL Server 2008语句,如果同时多次调用相同的.aspx页面,有时会导致死锁.建议的解决方案是使用SQL服务器手段来防止这些死锁,但我的问题是我不太了解它,这对C#来说并不正确,我知道的方式更好.
所以我想知道,我在ASP.NET页面中使用锁(或者在C#中锁定,或者是名为mutex的锁)而不是通过SQL服务器进行锁定来防止这些死锁,这有什么缺点?
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
}
}
Run Code Online (Sandbox Code Playgroud)
这里有一个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
Run Code Online (Sandbox Code Playgroud)
什么是我使用的ASP.NET页锁(或锁在C#中,或Windows命名的互斥体),而不是做通过SQL服务器锁定,以防止这些死锁的缺点?
而不是导致死锁,你将导致活锁.
当等待图包含一个循环(A等待B,B等待A)时发生死锁.SQL Server定期检查所有等待图并查找周期.当检测到一个这样的循环时,通过选择受害者并中止其交易来打破循环.
如果您将其中一些锁移到SQL Server控制的域之外,即.在进程互斥体,关键部分,C#事件或其他什么时候,等待图循环仍然会发生,但现在循环将通过应用程序完成,因此SQL Server将无法检测到(A在SQL中等待B,但是B等待A在应用程序中).由于死锁监视器不会看到循环,它将不会运行死锁解析算法(选择受害者,中止它的事务)并且死锁将永远保持.恭喜,现在您的应用程序只是挂起而不是引发死锁异常!
你不需要接受我的话,其他更有经验的人已经被这个问题所灼烧并且学到了很多东西,但幸运的是写了这篇文章,这样你就可以学到简单的方法.您正在阅读的这个网站就是一个例子.
一旦理解了问题,解决SQL Server中的死锁就相当容易了.如果您捕获并附加死锁图(XML,而不是图片!),以及表的确切定义,也许我们可以提供帮助.唉,你已经忽略了这样的要求所以我想唯一要问的问题是你想要更多的绳子吗?