C# 使用用户特定的锁防止重复的用户事务?

C# 使用用户特定的锁防止重复的用户事务?,c#,asp.net,locking,race-condition,C#,Asp.net,Locking,Race Condition,我们有一个传统的ASP.NET 2.0环境,其中每个页面执行都经过特定用户的身份验证,因此我有一个整数表示登录用户的ID 在其中一个页面上,我需要运行一些代码,以防止用户执行重复操作。发现很难保证这不会发生,即使我们正在进行基本的防重复检查 显然,我可以创建一个静态对象,并对整个代码段执行lock(myObject){…},以尝试并帮助防止某些竞争条件。但我不想给每个人造成瓶颈。。。只是想阻止同一个登录用户同时或几乎同时运行代码 因此,我考虑为每个用户创建一个对象实例,并根据他们的用户id将其存

我们有一个传统的ASP.NET 2.0环境,其中每个页面执行都经过特定用户的身份验证,因此我有一个整数表示登录用户的ID

在其中一个页面上,我需要运行一些代码,以防止用户执行重复操作。发现很难保证这不会发生,即使我们正在进行基本的防重复检查

显然,我可以创建一个静态对象,并对整个代码段执行
lock(myObject){…}
,以尝试并帮助防止某些竞争条件。但我不想给每个人造成瓶颈。。。只是想阻止同一个登录用户同时或几乎同时运行代码

因此,我考虑为每个用户创建一个对象实例,并根据他们的用户id将其存储在缓存中。然后我查找该对象,如果找到该对象,我将锁定它。如果找不到,我首先创建/缓存它,然后锁定它

这有意义吗?有没有更好的方法来完成我的目标

我是这么想的:

public class MyClass
{
    private static object lockObject = new object(); // global locking object

    public void Page_Load()
    {
        string cachekey = "preventdupes:" + UserId.ToString();
        object userSpecificLock = null;

        // This part would synchronize among all requests, but should be quick
        // as it is simply trying to find out if a user-specific lock object 
        // exists, and if so, it gets it. Otherwise, it creates and stores it.

        lock (lockObject)
        {
            userSpecificLock = HttpRuntime.Cache.Get(cachekey);
            if (userSpecificLock == null)
            {
                userSpecificLock = new object();

                // Cache the locking object on a sliding 30 minute window
                HttpRuntime.Cache.Add(cachekey, userSpecificLock, null,
                    System.Web.Caching.Cache.NoAbsoluteExpiration, 
                    new TimeSpan(0, 30, 0), 
                    System.Web.Caching.CacheItemPriority.AboveNormal, null);
            }
        }

        // Now we have obtained an instance of an object specific to the user, 
        // and we'll lock the next block of code specifically to them.

        lock (userSpecificLock)
        {
            try
            {
                // Perform some operations to check our database to see if the
                // transaction already occurred for this user, and if not, 
                // perform the transaction, and then record it into our db.
            } 
            catch (Exception)
            {
                // Rollback anything our code has done up until this exception,
                // so that if the user tries again, it will work.
            }
        }
    }
}
解决办法是使用

Mutex可以命名,因此您可以命名您的用户id,并且它们适用于整个计算机,因此,如果您在同一个池(web garden)下有多个进程,则它们可以工作

更多内容请阅读:



几点
该锁仅在同一线程和父线程内工作,您只能将其用于同步静态变量。但是
HttpRuntime.Cache
也是一个静态内存,这意味着如果在同一个池(web garden)下有许多进程,那么就有许多不同的缓存变量

该页面也由会话自动同步。因此,如果您已禁用此页面的会话,则互斥锁有一个点,如果没有,会话all ready将锁定页面加载(使用互斥锁),并且您将放置的互斥锁没有任何意义

关于:



也许考虑使用一个静态的<代码>用户ID <代码> >代码>锁定对象< /代码>对,而不是直接修改<代码> HTTPRunTime.Cache < /Cord>。互斥对象,非常有趣。关于ASP.NET使用会话锁定页面加载的观点也让我大吃一惊。我从未意识到这一点,我已经在ASP.NET上工作了10年。哎呀。