繁体   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