【发布时间】:2015-06-24 23:00:49
【问题描述】:
在我的 c# 代码中,我使用以下方法在数据库中创建文档,将有关文档的元数据添加到数据库中,然后更新有关存储库上次更新日期的一些信息。由于多个文件上传很常见,因此此方法通常会快速连续调用多次。但是,由于 sql server 中的死锁,我遇到了代码失败的问题。
private IEnumerable<DocumentMetadata> CreateDoc(int? jobId, int?repositoryId, int? folderId, string documentTypeString, IEnumerable<DocumentModel> files)
{
if ((jobId == null && repositoryId == null) || (jobId != null && repositoryId != null))
{
throw new InvalidOperationException("Either job id or repository id must be specified");
}
using (var tran = new TransactionScope())
{
List<DocumentMetadata> newDocuments = new List<DocumentMetadata>();
var documentType = GetDocumentTypeByPrefix(documentTypeString);
if (folderId == null)
{
// Find the root folder
var job = getJob(jobId);
var rootFolder = getRootFolder(job);
// If we can't find a root folder, create one
if (rootFolder == null)
{
rootFolder = CreateRootDirectory(job);
}
folderId = rootFolder.FolderId;
}
User currentUser = _userService.GetCurrentUser();
foreach (var file in files)
{
var document = new Document() { Document1 = file.Data };
var documentMetadata = new DocumentMetadata
{
Document = document,
CreatedDate = file.CreatedDate,
FileName = file.Filename,
FileSize = file.Data.Length,
FolderId = folderId,
DocumentType = documentType,
JobId = jobId,
RepositoryId = repositoryId,
User = currentUser
};
_unitOfWork.DocumentMetadata.Add(documentMetadata);
newDocuments.Add(documentMetadata);
}
// set repository updated date
if (repositoryId != null)
{
DocumentRepository repo = GetDocumentRepository(repositoryId);
if (repo != null)
{
repo.UpdatedDate = new DateTimeOffset(DateTime.Now);
}
}
_unitOfWork.SaveChanges();
tran.Complete();
return newDocuments;
}
}
经过一些调试后,似乎更新存储库 id 会导致死锁问题。如果我在事务之外删除此代码块,则所有文件都将保存而没有错误。
为什么这段代码会阻塞
if (repositoryId != null)
{
DocumentRepository repo = GetDocumentRepository(repositoryId);
if (repo != null)
{
repo.UpdatedDate = new DateTimeOffset(DateTime.Now);
}
}
导致死锁?除此方法外,没有对 DocumentRepository 表进行其他访问 - 因为锁是以相同的顺序获得的,所以肯定不应该出现死锁吗?
这段代码导致死锁的原因是什么?
更新:GetDocumentRepository 的代码是:
public DocumentRepository GetDocumentRepository(int repositoryId)
{
var result = DocumentRepositories.SingleOrDefault(x => x.RepositoryId == repositoryId); return result;
}
【问题讨论】:
-
我通过检查是否有任何使用的物品没有得到妥善处理而获得了声誉积分。这种行为是该根本原因的典型,我没有在代码中看到 using 语句或调用 dispose。当第二次执行期间正在访问的物理资源在第一次执行中没有被释放时,就会发生死锁。现在我没有时间通过代码来写一个正式的答案,但我希望这会有所帮助。
-
你能告诉我们
DocumentRepository repo = GetDocumentRepository(repositoryId);的代码 -
public DocumentRepository GetDocumentRepository(int repositoryId) { var result = DocumentRepositories.SingleOrDefault(x => x.RepositoryId == repositoryId); return result; } -
@nothingman - 编辑问题以添加代码比将其放入 cmets 中要好得多。当您添加代码时,最好在问题的末尾添加代码,以便每个人都可以轻松地跟踪更改。
-
@nothingman - 我认为您还应该添加填充
DocumentRepositories的代码。
标签: c# sql-server database-deadlocks