32

我使用 Asp.net mvc 4 (c#) 构建自己的 cms,我想缓存一些数据库数据,例如:本地化、搜索类别(它是长尾,每个类别都有自己的子类别和子子类别)等..

一直查询数据库会有点大材小用,因为每个页面请求可能会超过 30-100 次查询,但是用户很少更新这些数据库

那么最好的方法(性能和便利性)是什么?

我知道如何使用操作的 OutputCache,但这不是我在这种情况下需要的,它是缓存 html,但我需要的是,例如,我自己的助手@html.Localization("Newsletter.Tite")将获取语言的值,或者任何其他助手与数据等交互。

我认为(不太确定)我需要缓存我想要的数据,只有在第一次调用应用程序时,然后使用缓存位置,但我什至没有任何经验。

4

3 回答 3

39

您可以使用内置MemoryCache存储从数据库中检索到的整个结果集。

一个典型的模式:

MyModel model = MemoryCache.Default["my_model_key"] as MyModel;
if (model == null)
{
    model = GetModelFromDatabase();
    MemoryCache.Default["my_model_key"] = model;
}

// you could use the model here
于 2013-07-15T11:31:17.380 回答
36

我必须缓存常见的数据库数据,比如下拉菜单中显示的数据。我用过MemoryCache。我使用Entity Framework code firstandAutofac进行依赖注入。

这是我在解决方案中所做的部分工作,可能对您不起作用,但对我有用,虽然并不完美,但需要进行大量清理工作。

我的ICacheManager界面:

public interface ICacheManager
{
     T Get<T>(string key);

     void Set(string key, object data, int cacheTime);

     bool IsSet(string key);

     void Remove(string key);

     void Clear();
}

我的CacheManager班级:

public class CacheManager : ICacheManager
{
     private ObjectCache Cache
     {
          get
          {
               return MemoryCache.Default;
          }
     }

     public T Get<T>(string key)
     {
          return (T)Cache[key];
     }

     public void Set(string key, object data, int cacheTime)
     {
          if (data == null)
          {
               return;
          }

          CacheItemPolicy policy = new CacheItemPolicy();
          policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);

          Cache.Add(new CacheItem(key, data), policy);
     }

     public bool IsSet(string key)
     {
          return (Cache.Contains(key));
     }

     public void Remove(string key)
     {
          Cache.Remove(key);
     }

     public void Clear()
     {
          foreach (var item in Cache)
          {
               Remove(item.Key);
          }
     }
}

我的缓存的扩展类:

public static class CacheExtensions
{
     public static T Get<T>(this ICacheManager cacheManager, string key, Func<T> acquire)
     {
          return Get(cacheManager, key, 60, acquire);
     }

     public static T Get<T>(this ICacheManager cacheManager, string key, int cacheTime, Func<T> acquire)
     {
          if (cacheManager.IsSet(key))
          {
               return cacheManager.Get<T>(key);
          }
          else
          {
               var result = acquire();

               cacheManager.Set(key, result, cacheTime);

               return result;
          }
     }
}

这就是我在存储库类中使用它的方式。此方法返回我所有银行的列表,该列表显示在下拉列表中。

public class BankRepository : RepositoryBase<Bank>, IBankRepository
{
     private readonly ICacheManager cacheManager;
     private const string BanksAllCacheKey = "banks-all";

     public BankRepository(IDatabaseFactory databaseFactory, ICacheManager cacheManager)
          : base(databaseFactory)
     {
          Check.Argument.IsNotNull(cacheManager, "cacheManager");

          this.cacheManager = cacheManager;
     }

     public IEnumerable<Bank> FindAll()
     {
          string key = string.Format(BanksAllCacheKey);

          return cacheManager.Get(key, () =>
          {
               var query = from bank in DatabaseContext.Banks
                           orderby bank.Name
                           select bank;

               return query.ToList();
          });
     }
}

我希望这有帮助。这是一个非常简单的实现,但它对我有用。网上有很多关于如何使用缓存策略的文章ASP.NET MVC。只是Google它。

于 2013-07-15T12:11:43.133 回答
4

在选择缓存的实现之前,这里有几件事情需要考虑,但是您必须决定的主要事情之一是您希望缓存在什么时候发生 - 在数据访问、模型创建或 UI 生成时?一个或所有这些地方?

您有多种选择,但对于一般数据缓存,您可以使用 . System.Runtime.Caching.MemoryCache,或者对于更灵活和更有价值的东西,您可以查看使用 NoSQL 的实现,例如Redis

您可以使用MemoryCache数据缓存,但使用 Redis 缓存构成视图模型的聚合。如果您使用 Redis,您当然可以使用它来处理所有缓存。好处是您的所有数据将在应用程序重新启动时保持不变。缺点是它成为运行 CMS 的额外要求。

其他需要考虑的因素是一致性(使用一些 IoC 会有所帮助)并允许数据在更新后失效。因此有一些更新缓存的方法。

关于最佳方法,如果您正在创建新的 CMS 应用程序,请从小/简单开始并逐步构建。您可能第一次无法做到完美,但只要您的方法始终如一且清晰,就应该很容易在您已完成的工作或换掉并尝试不同/更好的东西的基础上进行构建。

于 2013-07-15T11:39:25.807 回答