我正在多線程環境中對SQL事務進行一些測試。我正試圖通過在一個循環中執行單個存儲過程來生成死鎖,這個過程由2個以並行方式運行的線程執行。我的兩個線程的使用上開始同樣的方法,連續執行一個存儲過程:單存儲過程和多線程的死鎖
using (TestDataContext db = new TestDataContext())
{
while (true)
{
db.DeadLocking();
}
}
能有人給「死鎖」的存儲過程,將可靠地在這種情況下塞納里奧產生死鎖的例子。它必須使用交易(單個或多個)。我已經研究了很多,並且看到了很多關於如何在sql中產生死鎖的例子,但是,他們都沒有在我的代碼中工作。請幫忙。
更新:繼馬克的建議,我想這個存儲過程無濟於事:
CREATE PROCEDURE [dbo].[DeadLocking]
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
SET NOCOUNT ON
BEGIN TRANSACTION
DECLARE @val varchar(1)
SELECT @val = Record FROM Test.dbo.Records WHERE RecordId = 1
UPDATE Test.dbo.Records SET Record = @val WHERE RecordId = 1
COMMIT TRANSACTION
END
從應該鎖定在那些海誓山盟線程都相同常線程中運行它。我究竟做錯了什麼?
更新:上述過程確實會導致死鎖,但是,至少需要3個線程才能完成此操作(不知道爲什麼,可能需要2個,但也需要永久)。有趣的是,這也導致僵局:
CREATE PROCEDURE [dbo].[DeadLocking]
AS
BEGIN
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
UPDATE Test.dbo.Records SET Record = 1 WHERE RecordId = 1
END
我猜是因爲存儲過程本身實現某種幕後事務邏輯的。如果任何人有關於爲什麼發生的更多信息,請分享。 請注意,死鎖只發生在UPDATE上,並且不會發生在SELECT上。這發生在SERIALIZABLE和REPEATABLE READ隔離級別上。
經典的死鎖方式:使用「serializable」隔離級別,有spid A對某些數據(沒有'updlock')執行讀鎖定;有spid B對相同的數據*進行讀取鎖定;現在如何spid A對同一數據進行寫入鎖定(嘗試更改列),並讓spid B嘗試執行相同的操作。他們現在都在彼此之間僵持不下。 – 2014-09-30 07:31:07
@Marc,我不假設簡單的SELECT會在一行上得到一個讀鎖,對嗎? – Alxg 2014-09-30 08:00:40
在可序列化的隔離級別;是的:會的。在大多數其他隔離級別中:否 – 2014-09-30 08:01:00