【问题标题】:Why am I getting a deadlock when my code is accessed multiple times?为什么我的代码被多次访问时会出现死锁?
【发布时间】: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 =&gt; x.RepositoryId == repositoryId); return result; }
  • @nothingman - 编辑问题以添加代码比将其放入 cmets 中要好得多。当您添加代码时,最好在问题的末尾添加代码,以便每个人都可以轻松地跟踪更改。
  • @nothingman - 我认为您还应该添加填充 DocumentRepositories 的代码。

标签: c# sql-server database-deadlocks


【解决方案1】:

您是否在未明确定义事务的情况下检查了代码?根据您的代码,我会说您正在尝试阅读已修改但未提交的内容。 您可以做的另一个测试是尝试在代码中添加断点并尝试使用 READ UNCOMMITTED 获取 DocumentRepository。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多