1

我与多工作线程的控制台应用程序,其中每个线程基本上尝试获取TOP 1“文件”一行满足一定的标准,并锁定它。(有一个LockID列其中当下一个线程拿起下一个可用的'解锁的''文件'行)多线程应用程序死锁问题与数据库

我们在SQL Server数据库上放置了一个监视器,并且每次在2个查询中发生死锁。

SELECT TOP 1 F.Id, F.ContentTypeId, F.ManufacturerId, F.DocumentTypeId, F.Name, F.Description, F.VersionId, F.LastChangedVersionOn, F.ReferenceCount, F.LastChangedReferencesOn, F.LastChangedImageOn, F.ImageSize, F.IsStale, F.InvalidFile, CT.Id, CT.Name, CT.MimeType, CT.IsMimeAttachment, CT.Extensions, CT.CanTrackVersions, CT.UseRemoteSource, CT.FullTextFilter, CT.ContentHandler, V.Id, V.Size, V.Hash, V.Title, DT.Id, DT.Code, DT.Ordinal, DT.Name, DT.PluralName, DT.UrlPart 
FROM Docs.Files F 
INNER JOIN Docs.ContentTypes CT ON CT.Id = F.ContentTypeId 
LEFT JOIN Docs.Versions V ON V.Id = F.VersionId 
LEFT JOIN Docs.DocumentTypes DT ON DT.Id = F.DocumentTypeId 
WHERE (F.LockId IS NULL OR F.LockedOn < DATEADD(hh,-1,GETUTCDATE())) 
AND F.IsStale = 1 AND F.InvalidFile = 0 

(@Id int)UPDATE Docs.Files 
SET LastChangedImageOn = GETUTCDATE(), ImageSize = (
    SELECT DATALENGTH(FileImage) 
    FROM Docs.FileImages 
    WHERE FileId = @Id) 
WHERE Id = @Id; 
SELECT TOP 1 LastChangedImageOn FROM Docs.Files WHERE Id = @Id  

第一个查询中创建一个新的线程时运行,我们试图获得一个新的“文件”行。

第二查询运行时线程(可以是先前创建的一个)上这个查询几乎与处理“文件”完成record.Used交易。隔离级别是“ReadCommitted”。 我很确定这两个查询都没有尝试访问相同的“FileID”,因为两个线程永远不会处理相同的“FileID”。 我非常困惑,我该如何诊断这个问题。什么可能导致这两个查询之间的死锁? 我真的很感激,如果有人能指引我在正确的方向。非常感谢提前:)

+1

这将有助于获得更多信息。 - 您使用哪个数据库服务器和引擎(如果适用)? - 你在使用交易吗?附: SQL代表结构化查询语言。有很多DB使用SQL。 – Paul

+1

这是什么隔离级别? –

+1

此外,我可以看到的唯一争用是在Docs.Files - 读取和写入,可以想象得到咆哮...选项:使读取工作与更少(零)隔离,所以它不会读取锁;或者使读*多*隔离,所以它需要一个写锁(导致阻塞而不是死锁)。这听起来更可取? –

回答

1

嗯...它,因为我没有与SQL Server什么已经有一段时间。但我们试试吧。

你提到“两个线程永远不会处理相同的‘写到FileID’后来”,你怎么能知道这事呢? ID是否从线程外部的源中提供?

+0

,因为该行将被上一个线程锁定,并且下一个线程只会选取“未锁定”行和“unStale”行。 – karry

+1

看起来这里有问题。线程是否将其设置在数据库中?如果是这样的话,线程何时开始和何时完成更新之间的差距呢?另一个线程是否可以运行并收到相同的fileID? – Paul

+1

嗨。你是否设法找到解决问题的办法,并且我的问题是否指向正确的方向? – Paul