我正在使用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,所以我想唯一要问的问题是,您还想要更多绳子吗?
