MVC中的MemoryCache的目的是什么?

约翰·杜

我对正确使用MemoryCache有点困惑。

是否应该/可以将其用于加载静态信息以节省重复的呼叫?是否应该/可以将其用于通过多种操作方法将数据持久化在视图上?

我有一个实例,我不想使用数据存储来填充和持久保存整个视图中的数据。我开始使用工作正常的MemoryCache,但是我开始怀疑这是否是正确的方法。

我担心的是,如果我在同一页面上有多个用户使用同一个MemoryCache,会发生什么情况?

夜猫子888

首先,MemoryCacheSystem.Runtime.Caching名称空间的一部分它可以由MVC应用程序使用,但不仅限于MVC应用程序。

注意:还有一个System.Web.Caching名称空间(较旧)只能与ASP.NET框架(包括MVC)一起使用。


是否应该/可以将其用于加载静态信息以节省重复的呼叫?

是。

是否应该/可以将其用于通过多种操作方法将数据持久化在视图上?

是。如果您的视图使用相同的数据,则可以。或者,如果_Layout.cshtml页面上有需要缓存的数据,则可以在全局过滤器中完成

如果我在同一页面上有多个用户使用同一个MemoryCache,会发生什么情况?

默认情况下,缓存在所有用户之间共享。它专门用于将数据保留在内存中,因此不必在每次请求时都从数据库中获取数据(例如,结帐页面上用于填充所有用户的下拉菜单中的状态名称列表)。

缓存频繁更改一两秒钟的数据也是一个好主意,以防止大量并发请求成为对数据库的拒绝服务攻击。

缓存取决于唯一的密钥。通过使用户名或ID成为密钥的一部分,可以在高速缓存中存储各个用户信息。

var key = "MyFavoriteItems-" + this.User.Identity.Name;

警告:仅当您具有单个Web服务器时,此方法才有效。它不会扩展到多个Web服务器。会话状态(用于单个用户内存存储)是一种更具可扩展性的方法。但是,会话状态并不总是值得进行权衡的


典型的缓存模式

请注意,尽管它MemoryCache是线程安全的,但将其与数据库调用结合使用可以使操作跨线程。如果不进行锁定,则可能会导致对数据库的多个查询来在缓存过期时重新加载缓存。

因此,您应该使用仔细检查的锁定模式,以确保只有一个线程可以通过它来从数据库重新加载缓存。

假设您有一个浪费每个请求的列表,因为每个用户进入特定页面时都将需要该列表。

public IEnumerable<StateOrProvinceDto> GetStateOrProvinceList(string country)
{
    // Query the database to get the data...
}

要缓存此查询的结果,可以添加另一个具有双重检查锁定模式的方法,然后使用它来调用原始方法。

注意:一种常见的方法是使用装饰器模式使缓存对您的API无缝。

private ObjectCache _cache = MemoryCache.Default;
private object _lock = new object();

// NOTE: The country parameter would typically be a database key type,
// (normally int or Guid) but you could still use it to build a unique key using `.ToString()`.
public IEnumerable<StateOrProvinceDto> GetCachedStateOrProvinceList(string country)
{
    // Key can be any string, but it must be both 
    // unique across the cache and deterministic
    // for this function.
    var key = "GetCachedStateList" + country;

    // Try to get the object from the cache
    var stateOrProvinceList = _cache[key] as IEnumerable<StateOrProvinceDto>;

    // Check whether the value exists
    if (stateOrProvinceList == null)
    {
        lock (_lock)
        {
            // Try to get the object from the cache again
           stateOrProvinceList = _cache[key] as IEnumerable<StateOrProvinceDto>;

            // Double-check that another thread did 
            // not call the DB already and load the cache
            if (stateOrProvinceList == null)
            {
                // Get the list from the DB
                stateOrProvinceList = GetStateOrProvinceList()

                // Add the list to the cache
                _cache.Set(key, stateOrProvinceList, DateTimeOffset.Now.AddMinutes(5));
            }
        }
    }

    // Return the cached list
    return stateOrProvinceList;
}

因此,您调用GetCachedStateOrProvinceList,它将自动从缓存中获取列表,如果未缓存,则会自动将列表从数据库加载到缓存中。仅允许一个线程调用数据库,其余线程将等待直到填充高速缓存,然后在可用时从高速缓存返回列表。

另请注意,每个国家/地区的州或省的列表将被单独缓存。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章