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

Posted

技术标签:

【中文标题】如何缓存数据库表以防止在 Asp.net C# mvc 中出现许多数据库查询【英文标题】:How to cache database tables to prevent many database queries in Asp.net C# mvc 【发布时间】:2013-07-13 06:02:20 【问题描述】:

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

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

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

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

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

【问题讨论】:

你目前在做什么,为什么不工作? Romoku,我对数据库进行简单的 c# linq 查询,这有点矫枉过正,因为每个页面请求都有很多请求 【参考方案1】:

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

【讨论】:

这是最好的方法吗?我可以找到很多方法,但我不知道什么是最好的 最佳是一个主观概念。 MemoryCache 具有很强的可扩展性,是 .NET 4.0 中引入的新缓存机制。它可以很容易地扩展到使用分布式缓存,例如 memcached,如果您在 webfarm 中运行您的网站,这是必须的。 然后继续使用 MemoryCache。 MemoryCache 对数据库表一无所知。它适用于 .NET 对象。因此,理论上,如果您将数据库表加载到某个 .NET 对象(或对象集合)中,则可以将其存储到 MemoryCache 中,如我的回答所示。 其实你不应该扩展 MemoryCache。您应该扩展 ObjectCache。 Memcached 已经提供了可以直接使用的实现。你说的对。我没有正确表达自己。【参考方案2】:

我必须缓存常见的数据库数据,例如下拉菜单中显示的数据。我用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吧。

【讨论】:

很好的答案。我很想使用这种方法。允许在开发人员想要时“清除缓存”的能力(我一直在为我的 [OutputCache] 属性与我的持续时间作斗争......如果你能在这个实现上放置一个持续时间,我会更喜欢它...... . 没关系,在这里回答我自己的问题:msdn.microsoft.com/en-us/library/… 很好,但是我不想在获取返回 null 、 0 或空 IEnumerable 时缓存,如何修复扩展方法?谢谢 你可以通过查看开源购物平台nopcommerce来清理,他们使用自己的CacheManager,请查看他们的source和this的帖子,希望有所帮助. MVCForum 也使用了 CacheManger,它在 Github 上是开源的。【参考方案3】:

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

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

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

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

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

【讨论】:

以上是关于如何缓存数据库表以防止在 Asp.net C# mvc 中出现许多数据库查询的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 数据库和 .NET (C#) - 如何防止 SQL 注入

在 Asp.net C# 中创建动态控件,并缓存控件并绑定数据

我的 asp.net mvc Web 应用程序中的 OutputCache 设置。防止缓存的多种语法

c# asp.net GridView中如何删除一条记录后刷新页面

如何正确 URL 重写图像? C# ASP.NET

asp.net(C#) 如何截取ip地址