[英]Can I use C# locks to prevent SQL Server deadlocks in my web application?
我正在使用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在應用中)。 由於死鎖監視器不會看到周期,因此它將不會運行死鎖解析算法(選擇受害者,中止其事務),並且死鎖將永遠保持下去。 恭喜,現在您的應用程序只是掛起,而不是引發死鎖異常!
您不必信服我的話,這個問題已經使其他經驗豐富的人煩惱了,並且學到了艱辛的方法,但是幸運的是寫了此書,以便您可以學習簡單的方法。 您正在閱讀的這個站點就是一個例子 。
了解問題后,解決SQL Server中的死鎖就相當容易了。 如果您捕獲並附加死鎖圖 (XML,而不是圖片!)以及表的確切定義,也許我們可以提供幫助。 las, 您已經忽略了這樣的要求,所以我想唯一要問的問題是您是否還想要繩子?
沒有足夠的細節,找不到真正導致死鎖的位置,我可以猜測可能是由於鍵范圍導致了死鎖,這意味着死鎖發生在表t_log_2的索引上,因為您具有刪除和更新功能,所以它們肯定不是發生在同一行上,但它們可以發生在同一鍵范圍上,或者一個進程可以容納A范圍,請求B范圍,而另一個進程可以容納B范圍並請求A范圍。 您可以使用SQL事件探查器跟蹤死鎖並查看死鎖的確切位置。 或者,簡單地說,如果它不會對您的性能造成太大影響,則可以將事務隔離級別設置為[可重復讀取]甚至[可序列化]。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
....
BEGIN TRANSACTION
....
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.