线程安全数据库访问策略

Chi*_*han 2 c# asp.net-mvc multithreading dynamics-crm dynamics-crm-4

假设我有以下代码将用户插入MVC应用程序中的MS Dynamics:

public bool CreateContact(string email)
{
    if (crm.contacts.Count(x => x.Email == email) > 0)
         return false; //Email already exist in the Crm. Skip

    var contact = new contact {Email = email};
    crm.AddTocontacts(contact);
    crm.SaveChanges();

    return true;
}
Run Code Online (Sandbox Code Playgroud)

它非常适合阻止用户使用相同的电子邮件地址注册,直到最近我们遇到Dynamics的主要性能问题.

显然,用户会遇到很大的延迟,并经常三次点击触发此代码的按钮.

问题是,.Count()在不同的Http请求中同时触发.SaveChanges()在第一个Request中完成.因此,我们看到的联系人具有相同的电子邮件地址.

虽然我已经从客户端添加了一个修复程序,但我想看看是否可以在服务器端完成此操作.

什么是使这个线程安全的好策略?


编辑:

虽然在CRM中添加约束是最好的解决方案,但是我现在无法实现该解决方案,因为在发现此问题之前很久就存在CRM中的重复项.显然,有多个应用程序与CRM对话.

由于锁定和线程的经验很少,我最终做了以下事情:

internal static class ContactLock
{
    internal static readonly object Locker = new object();
}

public bool CreateContact(string email)
{
    lock(ContactLock.Locker)
    {
        if (crm.contacts.Any(x => x.Email == email))
            return false; //Email already exist in the Crm. Skip

        var contact = new contact {Email = email};
        crm.AddTocontacts(contact);
        crm.SaveChanges();

        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

它通过我的单元测试,似乎没有任何问题.

And*_*bel 5

这种验证通常应该由底层数据存储中的唯一约束支持.如果可以在CRM数据库中创建约束,那么修复应该在哪里.

您的代码段显示了需要某种锁定的典型位置.检查(带Count())和SaveChanges()应该由锁保护.我建议你先从锁定一个静态的对象开始 - 这意味着它将是一个防止同时注册的全局锁.如果这证明是一个问题,你可以修改锁定策略.

关于电话花了很多时间 - 这是你应该解决的问题.向电子邮件列添加唯一约束将强制将其编入索引,这可能会大大提高性能.如果可能(再次,我不知道CRM)你应该使用linq的Any()运算符而不是Count()检查是否存在.前者可以在第一次打击时打破,而后者则必须继续扫描.

  • @usr:Dynamics CRM不允许以您建议的方式直接访问数据库,因此数据库唯一索引(具有已处理的数据上下文)可能是唯一的方法. (3认同)