【问题标题】:Why this lock does not work in service, called from asp.net?为什么这个锁在服务中不起作用,从 asp.net 调用?
【发布时间】:2015-08-26 11:11:33
【问题描述】:

我继承了一个应用程序,该应用程序具有从 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)。

【问题讨论】:

    标签: c# asp.net multithreading locking structuremap


    【解决方案1】:

    由于锁是一个静态变量,因此每个应用程序域只有一个这样的锁对象,这排除了许多可能的错误。这是我能想到的这个问题的唯一原因:

    您的锁仅适用于一个应用程序域。 ASP.NET 可以同时在多个应用程序域中运行应用程序,例如在回收、部署或网络花园模式下。此外,您可能有多个服务器。

    最好的解决方法是使_idGenerationService.GetNextId 线程安全。您可能需要对作为此方法基础的数据库查询应用适当的锁定。

    另外,你的锁定区域太长了。您还包括插入到数据库中。这会导致并发性不足,并可能导致分布式死锁。

    【讨论】:

    • 我从您的回答中学到了很多东西,只是一个简短的评论。 “最好的解决方法是使_idGenerationService.GetNextId 线程安全”。但是该方法只是从数据库中读取,因此在稍后调用 InsertOrUpdate() 之前它不会返回不同的值。因此我锁定了整个方法。
    • 我明白了。那么也许您应该将 ID 生成移到作用于该 ID 的事务中。从业务角度来看,这可能就是我们想要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-30
    • 2021-03-29
    相关资源
    最近更新 更多