C# 使用HttpRuntime.Cache时出现问题

C# 使用HttpRuntime.Cache时出现问题,c#,asp.net,caching,C#,Asp.net,Caching,我使用以下.net代码将对象添加到缓存: public static void Add<T>(string key, T dataToCache) { try { ApplicationLog.Instance.WriteInfoFormat("Inserting item with key {0} into Cache...", key); HttpRuntime.Cache.Insert( key,

我使用以下.net代码将对象添加到缓存:

public static void Add<T>(string key, T dataToCache)
{
    try
    {
        ApplicationLog.Instance.WriteInfoFormat("Inserting item with key {0} into Cache...", key);

        HttpRuntime.Cache.Insert(
            key,
            dataToCache,
            null,
            DateTime.Now.AddDays(7),
            System.Web.Caching.Cache.NoSlidingExpiration);
    }

    catch (Exception ex)
    {
        ApplicationLog.Instance.WriteException(ex);             
    }
}
publicstaticvoidadd(字符串键,T dataToCache)
{
尝试
{
ApplicationLog.Instance.WriteInfo格式(“将具有项{0}的项插入缓存…”,项);
HttpRuntime.Cache.Insert(
钥匙
dataToCache,
无效的
DateTime.Now.AddDays(7),
System.Web.Caching.Cache.NoSlidingExpiration);
}
捕获(例外情况除外)
{
ApplicationLog.Instance.WriteException(ex);
}
}
下面是我从缓存中检索值的代码:

public static T Get<T>(string key) 
{   
    try
    {                
        if (Exists(key))
        {
            ApplicationLog.Instance.WriteInfoFormat("Retrieving item with key {0} from Cache...", key);

            return (T)HttpRuntime.Cache[key];
        }
        else
        {
            ApplicationLog.Instance.WriteInfoFormat("Item with key {0} does not exist in Cache.", key);
            return default(T); 
        }
    }
    catch(Exception ex)
    {
        ApplicationLog.Instance.WriteException(ex);
        return default(T); 
    }
}


public static bool Exists(string key)
{
    bool retVal = false;
    try
    {
        retVal= HttpRuntime.Cache[key] != null;
    }
    catch (Exception ex)
    {
        ApplicationLog.Instance.WriteException(ex);
    }
    return retVal; 
}
publicstatict-Get(字符串键)
{   
尝试
{                
如果(存在(键))
{
ApplicationLog.Instance.WriteInfo格式(“正在从缓存中检索具有项{0}的项…”,项);
return(T)HttpRuntime.Cache[key];
}
其他的
{
ApplicationLog.Instance.WriteInfo格式(“缓存中不存在键为{0}的项。”,键);
返回默认值(T);
}
}
捕获(例外情况除外)
{
ApplicationLog.Instance.WriteException(ex);
返回默认值(T);
}
}
存在公共静态bool(字符串键)
{
bool-retVal=false;
尝试
{
retVal=HttpRuntime.Cache[key]!=null;
}
捕获(例外情况除外)
{
ApplicationLog.Instance.WriteException(ex);
}
返回返回;
}
但我发现每隔2分钟左右,缓存的对象值就会被设置为null,从而再次从数据库中提取该值


我在这里遗漏了什么?

可能是因为内存不足,当内存不足时,缓存会自动删除缓存中的项目,如果您希望先清除一个项目,然后再清除另一个项目,则有一个可选参数用于设置缓存中项目的优先级。

当您说每两分钟插入的值设置为null时,这是指您感兴趣的项目还是缓存中的每个项目

我这样问是因为缓存只在应用程序运行时存在。如果重新启动应用程序,缓存将消失。这就解释了如果每两分钟所有东西都消失一次的行为。在这种情况下,您会遇到另一个问题:为什么应用程序每2分钟重启一次

如果只是一些项目,那么可能是内存问题。缓存会根据内存不足自行清理。我相信有一种方法可以设置插入值的优先级。但这只会在内存不足时出现问题


如果这仍然不能解决您的问题,那么有一种方法可以发现删除项目的原因。这已经解释清楚了。

首先,您的访问是不同步的,所以这是一个很大的问题来源。从HttpRuntime缓存读取是线程安全的,因此您应该真正尝试读取项目,作为每次缓存操作的第一步

在检查
是否存在
和实际检索物品之间,可能会发生很多事情(例如你的物品不再存在)。您应该获得要查找的项目的句柄,如果它不存在,则通过从持久数据存储中获取它来提供线程安全的插入

因此,如果数据不存在,
Add
逻辑将进入
get
内部。提供单独的
Add
逻辑从根本上讲没有什么错,与阻止对特定数据段的进一步请求相比,您应该衡量多次访问数据库的成本

T GetT(string key)
{
    T item = (cache.Get(key) as T);
    if (item == null)
    {
        lock (yourSyncRoot)
        {
            // double check it here
            item = (cache.Get(key) as T);
            if (item != null)
                return item;

            item = GetMyItemFromMyPersistentStore(key); // db?
            if (item == null)
                return null;

            string[] dependencyKeys = {your, dependency, keys};

            cache.Insert(key, item, new CacheDependency(null, dependencyKeys), 
                         absoluteExpiration, slidingExpiration, priority, null);
        }
    }
    return item;
}

根据您的过期策略,您将在内存中获取数据,并提供对数据的快速同步访问,但正如我所说的,测量数据并根据您的需要进行调整。在您的业务逻辑中,在更新项目并将其正确保存到持久存储之后,只需将其从缓存中删除,下一次调用您的
Get
将再次获取它。

我认为使用缓存的代码会更相关。例如,您是否多次将同一密钥添加到缓存中?因为他正在使用insert,如果该项已在缓存中,则只会更新该项。您的ASP.NET配置是默认设置吗?例如,ASP.NET是否因某种原因被设置为在分配了一定数量的内存后循环使用,或者时间已过?您的应用程序池设置如何?基本上,您确定没有重新启动HttpRuntime吗?请注意,Get()方法中存在潜在的竞争条件,因为可以在exists()调用和HttpRuntime.cache[key]之间更新缓存。请参阅此处的最后一点:感谢您的输入…是的,缓存中的每个项目的值都设置为null。您可以检查日志以确认应用程序是否正在重新启动,如果是,原因是什么?一旦你发现你应该能够解决它或张贴另一个问题。这可能会有所改进我添加一个lambda到Get并使其成为一个扩展方法。。。静态T Get(此缓存、字符串键、Func retrieveFunc)@eych,“缓存访问是线程安全的”意味着对象上的单个操作以原子方式运行,并且在被多个线程命中时不会导致失败。但是,即使对于线程安全的集合,对象上的多个操作仍然需要通过锁进行同步。这里我们有一个“Get”和一个“Insert”,如果Get没有找到对象。必须锁定该对,否则两个或多个不同的线程可能会通过“Get”,而不是查找对象,以及创建和“插入”对象。如果我们只需要一个线程来创建和插入对象,那么必须锁定操作对。共同模式。