4

我到处读到,如果 Add 方法已经存在,它会失败,但它会抛出异常还是静默失败?

我正在编写一个不应该存在的多线程 Web 应用程序,如果我覆盖缓存会导致问题,所以我不能使用 Insert 方法。

这是我可以做的事情吗:

try
{
    HttpContext.Current.Cache.Add("notifications", notifications, null,
      System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromHours(8),
      System.Web.Caching.CacheItemPriority.High, null);
}
catch
{
    //do whatever if notifications already exist
}

感谢您的任何答案:)

4

3 回答 3

13

System.Web.Caching.Cache被设计为在多线程 Web 应用程序中是线程安全的,并且多个线程可能会争用将相同的键添加到缓存中。所以这取决于你想如何处理这种竞争条件。

  • 在许多情况下,您会将不可变数据插入缓存中,而不会关心哪个线程“赢得”比赛。所以你可以使用Addor Insert

  • 如果您想要“第一个获胜”,请使用该Add方法,如果您想要“最后一个获胜(并覆盖)”,请使用该Insert方法。

  • 在插入/添加之前检查是否存在是没有意义的。另一个线程可能会在您检查之后和您尝试添加/插入之前插入该项目。

  • 如果密钥已经存在,也Add不会Insert抛出异常。这样做是没有意义的,因为 Cache 是为无需锁定的线程安全插入而设计的。 Add将静默失败,并Insert覆盖。

  • 顺便说一句,从缓存中读取时,不要检查是否存在,然后读取:

    if (Cache["MyKey"] == null)
    {
        // ... handle missing value
    }
    else
    {
        // ... a race condition means the item may have been removed here
        // before you get a chance to read it
    
        MyType value = (MyType) Cache["MyKey"];
    }
    

    相反,从缓存中读取值并检查是否为空:

    MyType value = Cache["MyKey"] as MyType; // for reference types
    if (value == null)
    {
        // ... handle missing value
    }
    
于 2012-07-11T12:39:18.983 回答
0

这很容易测试自己,但会引发错误。一个很好的实用功能:

    /// <summary>
    /// Places an item into the cache using absolute expiration.
    /// </summary>
    /// <param name="key">Key of the item being inserted</param>
    /// <param name="item">Item to insert</param>
    /// <param name="expireTime">Absolute expiration time of the item</param>
    public static void InsertIntoCacheAbsoluteExpiration(string key, object item, DateTime expireTime)
    {
        if (HttpContext.Current == null)
        {
            return;
        }

        lock (LOCK)
        {
            HttpRuntime.Cache.Remove(key);
            HttpRuntime.Cache.Add(
                key,
                item,
                null,
                expireTime,
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.Normal,
                null);
        }
    }

如果密钥不退出,删除不会抱怨。如果您想测试密钥是否已经存在,您可以随时检查

HttpRuntime.Cache.Get(key) != null

只要您使用锁定变量,您就不会遇到这样的问题:您的检查显示缓存中没有某些内容,并且它显示在检查和添加之间。

于 2012-07-11T12:24:50.353 回答
0

它默默地失败了。

using System.Web;
using System.Web.Caching;

class Program
{
    static void Main(string[] args)
    {
        Cache cache = HttpRuntime.Cache;

        string object1 = "Object1";
        string object2 = "Object2";

        cache.Add(
            "Key", object1, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0), CacheItemPriority.Normal, null);
        cache.Add("Key", object2, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0), CacheItemPriority.Normal, null);

        string cachedstring = (string)cache.Get("Key");

        Console.WriteLine(cachedstring);

        Console.ReadLine();
    }
}

此控制台应用程序的输出是Object1.

于 2012-07-11T12:27:37.593 回答