我可以在我的web应用程序中使用c#锁来防止SQL Server死锁吗?
本文关键字:SQL Server 死锁 web 我的 应用程序 我可以 | 更新日期: 2023-09-27 18:03:32
我正在使用c#在Visual Studio 2010中编写一个web应用程序。web应用程序执行复杂的SQL Server 2008语句,如果在同一时间多次调用同一个.aspx页面,有时会导致死锁。建议的解决方案是使用SQL server手段来防止这些死锁,但我的问题是,我真的不太了解它,这不是c#,我知道得更好。
所以我想知道,我在ASP中使用锁的缺点是什么。. NET页面(或c#中的锁,或Windows命名的互斥锁),而不是通过SQL服务器进行锁定来防止这些死锁?
p。此SQL Server数据库仅供此web应用程序使用。
EDIT:下面是执行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服务器进行锁定来防止这些死锁?
将导致活锁而不是死锁。
当等待图包含一个循环(A等待B, B等待A)时,会发生死锁。SQL Server定期检查所有的等待图并查找循环。当检测到一个这样的循环时,通过选择受害者并中止其事务来打破循环。
如果你把这些锁移到SQL Server控制域之外,例如:在进程互斥、临界区、c#事件或其他情况下,等待图周期仍然会发生,但现在这个周期将通过应用程序完成,因此SQL Server将无法检测到(A在SQL中等待B,但B在应用程序中等待A)。因为死锁监视器不会看到一个周期,所以它不会运行死锁解析算法(选择一个受害者,中止它的事务),并且死锁将永远保持。恭喜,现在您的应用程序只是挂起,而不是引发死锁异常!
你不必相信我的话,其他更有经验的人已经被这个问题烧伤了,并且吸取了惨痛的教训,但幸运的是,把它写下来,这样你就可以用简单的方法学习。你正在阅读的这个网站就是一个例子。
解决死锁在SQL Server是相当容易的,一旦你明白了这个问题。如果捕获并附加死锁图(XML,而不是图片!)以及表的确切定义,也许我们可以提供帮助。唉,你已经忽略了这样的请求,所以我想唯一要问的问题是你想要更多的绳子吗?在不知道足够细节的情况下,无法找到真正导致死锁的地方,我可以猜测这可能是因为键范围导致了死锁,这意味着死锁发生在表t_log_2的索引上,因为你有删除和更新,它们肯定不是发生在同一行上,但它们可以发生在相同的键范围上,或者一个进程可以持有A范围,请求B范围,另一个进程可以持有B范围和请求A范围。您可以使用SQL Profiler跟踪死锁并查看死锁究竟发生在哪里。或者,简单地说,如果不会对性能造成太大影响,您可以将事务隔离级别设置为[repeatable read]甚至[serializable]。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
....
BEGIN TRANSACTION
....