如何缓存数据库表以防止在Asp.net C#mvc中进行许多数据库查询

时间:2013-07-15 11:24:14

标签: c# asp.net asp.net-mvc caching asp.net-mvc-4

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

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

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

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

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

3 个答案:

答案 0 :(得分:32)

我必须缓存常见的数据库数据,例如下拉列表中显示的数据。我用了MemoryCache。我使用Entity Framework code firstAutofac进行依赖注入。

以下是我在解决方案中所做的一部分,可能不适合你,但它对我有用,虽然不完美但需要大量的清理工作。

我的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

答案 1 :(得分:31)

您可以使用内置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

答案 2 :(得分:4)

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

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

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

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

关于最佳方法,在您的情况下,如果您要创建新的CMS应用程序,请从小/简单开始并逐步构建。你可能不会在第一时间得到完美,但只要你在你的方法中保持一致和清晰,就应该很容易建立在你所做的事情上,或者换掉并尝试不同/更好的事情。