我正在多线程环境中对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