簡體   English   中英

為什么從asp.net調用此鎖在服務中不起作用?

[英]Why this lock does not work in service, called from asp.net?

我繼承了一個具有服務類的應用程序,該服務類是從asp.net應用程序調用的,如下所示:

class PeopleService : IPeopleService
{
    //...
    public void SavePerson(Person person)
    {
        person.UniqueId = _idGenerationService.GetNextId(person);
        //...
        _dbContext.InsertOrUpdate(person);
        _dbContext.Commit();
    }
}

class IdGenerationService : IIdGenerationService
{
    //...
    public string GetNextId(Person person) 
    {
        int nextId = _dbContext.People.Count(x => x.Gender == person.Gender) + 1;
        return string.Format("AB{0}", nextId);
    }
}

GetNextId(Person)的實現不是線程安全的,並且我們有很多具有重復ID的Person對象,例如AB1,AB2,AB2等。

解決方案是將lock應用於SavePerson(Person)如下所示:

class PeopleService : IPeopleService
{
    private static readonly Object ReadIdLock = new Object();
    //...
    public void SavePerson(Person person)
    {
        lock(ReadIdLock) 
        {
            person.UniqueId = _idGenerationService.GetNextId(person);
            //...
            _dbContext.InsertOrUpdate(person);
            _dbContext.Commit();
        }
    }
}

現在,我們嘗試通過在asp.net應用程序中同時單擊“保存”按鈕來測試代碼。 但是修復沒有用! 有趣的是,只有第一個記錄似乎是重復的,例如AB1,AB1,AB2,AB3 ...

多個請求如何訪問鎖定的語句? 我應該改用Mutex嗎?

(請注意,該示例不是生產代碼,它是一個簡化的代碼,可以傳達我們遇到的問題。此外,一點點,我們將StructureMap用作DI)。

由於鎖是一個靜態變量,因此每個appdomain中只有一個這樣的鎖對象,它排除了許多可能的錯誤。 這是我能想到的唯一問題的原因:

您的鎖只能在一個appdomain中使用。 ASP.NET可以同時在多個應用程序域中運行應用程序,例如在回收,部署或以網絡花園模式運行時。 另外,您可能有多個服務器。

最好的解決方法是使_idGenerationService.GetNextId線程安全的。 可能您需要對作為此方法基礎的數據庫查詢應用適當的鎖定。

另外,您鎖定的區域太長。 您還將覆蓋插入到數據庫中。 這會使並發性不足,並可能導致分布式死鎖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM