简体   繁体   English

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

[英]How to cache database tables to prevent many database queries in Asp.net C# mvc

I build my own cms using Asp.net mvc 4 (c#), and I want to cache some database data, likes: localization, search categories (it's long-tail, each category have it's own sub and sub-sub categories), etc.. 我使用Asp.net mvc 4(c#)构建自己的cms,我想缓存一些数据库数据,例如:本地化,搜索类别(它是长尾,每个类别都有自己的子和子子类别),等等..

It's will be overkill to query the database all the time, because it can be more than 30-100 queries for each page request, however the users update those database rarely 查询数据库一直都是过度的,因为每个页面请求可以超过30-100个查询,但是用户很少更新这些数据库

So what is the best way (performance and convenience) to do it? 那么最好的方法(性能和便利性)是什么?

I know how use the OutputCache of the action, but it's not what I need in this situation , it's cache the html, but what I need is for example, that my own helper @html.Localization("Newsletter.Tite") will take the value of the language, or any another helper that interact with data etc. 我知道如何使用动作的OutputCache,但这不是我在这种情况下需要的,它是缓存html,但我需要的是例如,我自己的助手@html.Localization("Newsletter.Tite")将采取语言的价值,或与数据交互的任何其他帮助者等。

I think (not really sure) that I need to cache the data I want, only when the application is invoke for the first time, and then work with the cache location, but I don't have any experience even about to it. 我认为(不太确定)我需要缓存我想要的数据,只有在第一次调用应用程序时,然后使用缓存位置,但我甚至没有任何经验。

I had to cache common database data like data that were displayed in drop downs. 我不得不缓存常见的数据库数据,如下拉列表中显示的数据。 I used MemoryCache . 我用过MemoryCache And I used Entity Framework code first and Autofac for dependency injection. 我首先使用Entity Framework code first ,使用Autofac进行依赖注入。

Here is part of what I did in my solution, might not work for you but it worked for me, not perfect though but needs a lot of cleaning up to do. 这是我在我的解决方案中所做的一部分,可能不适合你,但它对我有用,虽然不完美但需要大量的清理工作。

My ICacheManager interface: 我的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();
}

My CacheManager class: 我的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);
          }
     }
}

An extension class for my caching: 我的缓存的扩展类:

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;
          }
     }
}

And this is how I would use it in my repository class. 这就是我在我的存储库类中使用它的方法。 This method returns a list of all my banks which is displayed in a drop down. 此方法返回所有银行的列表,该列表显示在下拉列表中。

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();
          });
     }
}

I hope this helps. 我希望这有帮助。 It's a very simple implementation but it works for me. 这是一个非常简单的实现,但它适用于我。 There are many articles online on how to use a caching strategy in ASP.NET MVC . 有很多关于如何在ASP.NET MVC使用缓存策略的文章。 Just Google it. 只是Google吧。

You could use the built-in MemoryCache to store entire resultsets you have retrieved from the database. 您可以使用内置的MemoryCache存储从数据库中检索到的整个结果集。

A typical pattern: 典型模式:

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

There are several things to consider here before choosing your implementation of caching, but one of the main things you have to decide is at what point do you want the caching to occur - at data access, the model creation or UI generation? 在选择缓存实现之前,有几点需要考虑,但是您必须决定的主要事项之一是您希望缓存发生在什么时候 - 数据访问,模型创建或UI生成? One or all of these places? 这些地方中的一个或全部?

You have several options but for general data caching you can use the System.Runtime.Caching.MemoryCache , or for something much more flexible and rewarding you can look at an implementation using NoSQL like Redis . 您有几个选项,但对于常规数据缓存,您可以使用System.Runtime.Caching.MemoryCache ,或者对于更灵活和有益的东西,您可以查看使用NoSQL的实现,如Redis

You could use MemoryCache for data caching, but use Redis for caching aggregates making up your view models. 您可以使用MemoryCache进行数据缓存,但使用Redis缓存构成视图模型的聚合。 If you went with Redis, you could of course handle all your caching using this. 如果您使用Redis,您当然可以使用此处理所有缓存。 The benefit being that all your data would become persistent across application restarts. 好处是所有数据在应用程序重新启动时都会保持不变。 The disadvantage being that it becomes an additional requirement for running your CMS. 缺点是它成为运行CMS的额外要求。

Other things to factor in are consistency (using some IoC would help) and allowing data to be voided once it updates. 其他要考虑的因素是一致性(使用一些IoC会有所帮助)并允许数据在更新后无效。 Therefore having some means of updating the cache. 因此有一些更新缓存的方法。

With regards to the best approach, in your case if you are creating a new CMS application, start small/simple and build up in steps. 关于最佳方法,在您的情况下,如果您要创建新的CMS应用程序,请从小/简单开始并逐步构建。 You may not get it perfect first time but as long as you are consistent and clear in your approach it should be easy to build upon what you have done or swap out and try something different/better. 你可能不会在第一时间得到完美,但只要你在你的方法中保持一致和清晰,就应该很容易建立在你所做的事情上或换掉并尝试不同/更好的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM