zoukankan      html  css  js  c++  java
  • 第十一节:Asp.Net Core 之内容缓存(IMemoryCache)

    1. 整体说明

      ASP.NET Core 支持多种不同的缓存,最简单的缓存基于 IMemoryCache,它表示存储在 Web 服务器内存中的缓存,内存缓存可以存储任何对象,存储形式键值对,需要 .net standard 2.0 或者 .Net framework 4.5 或更高版本。

    本节主要介绍:依赖注入的方式使用、全局封装单例配置、缓存几个方法和性质。

    2. 常规使用步骤

      (1) 安装程序集:System.Runtime.Caching 和 Microsoft.Extensions.Caching.Memory,如果是是Core MVC程序自带的Microsoft.AspNetCore.App包里已经涵盖了

     Microsoft.Extensions.Caching.Memory,无需重复下载。

      (2) 在ConfigureService中注册内存缓存服务: services.AddMemoryCache();

     1 using Microsoft.AspNetCore.Builder;
     2 using Microsoft.AspNetCore.Mvc;
     3 using Microsoft.Extensions.DependencyInjection;
     4 
     5 public class Startup
     6 {
     7     public void ConfigureServices(IServiceCollection services)
     8     {
     9         services.AddMemoryCache();
    10         services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    11     }
    12 
    13 
    14 }

      (3) 通过属性注入的方式在控制器中注入IMemoryCache对象。

    1  public class FirstController : Controller
    2     {
    3         private IMemoryCache _cache1;
    4         public FirstController(IMemoryCache memoryCache)
    5         {
    6             _cache1 = memoryCache;
    7         }
    8     }

      (4) 通过get、set方法实现常规缓存的读取和写入,如下 案例①。

    1    {
    2        string nowTime1 = _cache1.Get<string>("t1");
    3        if (String.IsNullOrEmpty(nowTime1))
    4        {
    5            nowTime1 = DateTime.Now.ToString();
    6            _cache1.Set("t1", nowTime1);
    7        }
    8        ViewBag.t1 = nowTime1;
    9   }

    3. 全局封装单例的形式

     (1)新建一个memoryCacheHelp类,声明一个IMemoryCache属性,并在构造函数中进行初始化,实例化的时候可以通过SizeLimit设置全局缓存的最大Size。

    特别注意:如果在这全局设置了最大Size,凡是使用的时候都需要通过SetSize进行设置,且必须 "小于等于" 这个最大Size,不设置会报错,设置的比这个大,缓存会失效。

     1  public class memoryCacheHelp
     2     {
     3         public IMemoryCache _cache { get; set; }
     4         public memoryCacheHelp()
     5         {
     6             _cache = new MemoryCache(new MemoryCacheOptions {
     7                 SizeLimit = 1024
     8             });
     9         }
    10     }

     (2)在ConfigureService将该类注册成单例的:services.AddSingleton<memoryCacheHelp>();

    1 public void ConfigureServices(IServiceCollection services)
    2 {
    3     services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    4     services.AddSingleton<memoryCacheHelp>();
    5 }

     (3)通过属性注入的方式在控制器中注入IMemoryCache对象

    1  public class FirstController : Controller
    2     {
    3         private IMemoryCache _cache2;
    4         public FirstController(memoryCacheHelp cache)
    5         {
    6             _cache2 = cache._cache;
    7         }
    8    }

     (4)通过TryGetValue、set方法实现缓存的读取和写入,如下 案例②

    注: 这里通过依赖注入的形式将memoryCacheHelp注册成单例类,和直接声明成单例类道理是一样的。

     1  {
     2      string nowTime2 = null;
     3      if (!_cache2.TryGetValue("t2", out nowTime2))
     4      {
     5          nowTime2 = DateTime.Now.ToString();
     6          //设置缓存的大小
     7          var cacheOptions = new MemoryCacheEntryOptions()
     8                                       .SetSize(100)
     9                                       .SetAbsoluteExpiration(TimeSpan.FromSeconds(5));
    10           _cache2.Set("t2", nowTime2, cacheOptions);
    11      }
    12     ViewBag.t2 = nowTime2;
    13 }

    4. 方法、属性详解

    (1) 获取数据

     A. Get<T>方法:根据键名获取指定类型的值,将返回值做判断,比如根据是否为null,来判断有没有值。 如下面的案例①

     B. TryGetValue(object key, out TItem value);根据key获取指定类型值,通过out参数进行输出,如果拿到值返回true,如果拿不到值返回false,相比Get<T>方法 如下面案例②

     C. GetOrCreate(object key, Func<ICacheEntry, TItem> factory);适用场景:key有值则获取该值,没有值为它赋值(通过return直接返回)。如下面案例③

    (2) 写入数据

     A. Set方法:有很多重载,重点看下面两个

      ①:Set<TItem>(object key, TItem value); 最简单的键值模式

      ②:Set<TItem>(object key, TItem value, MemoryCacheEntryOptions options); 通过MemoryCacheEntryOptions设置缓存的性质,详见下面

     B. GetOrCreate方法:当key对应的值为空则通过return返回来赋值,如下面的:案例③,通过第二个参数在Func委托中设置ICacheEntry属性进行缓存性质的设置。 详见下面(5)

     1 {
     2     string nowTime3 = _cache1.GetOrCreate("t3", entry =>
     3     {
     4       entry.Size = 100;
     5       //滑动过期时间设置为2秒
     6       entry.SlidingExpiration = TimeSpan.FromSeconds(2);
     7       //绝对和滑动只能设置一个
     8       //entry.AbsoluteExpiration = new DateTimeOffset(DateTime.Parse("2019-07-16 16:33:10"));
     9       entry.Priority = CacheItemPriority.High;
    10       entry.RegisterPostEvictionCallback(MyCallback, this);
    11       return DateTime.Now.ToString();
    12     });
    13     ViewBag.t3 = nowTime3;
    14 }

    (3) 移除数据

     A. Remove方法:Remove(object key); 移除缓存

    (4) MemoryCacheEntryOptions类

     用来设置缓存的一些性质,可以通过方法或者属性进行设置,在Set方法中使用。

     A. 缓存大小(SetSize方法和Size属性):如果全局单例设置缓存的最大值,则每个使用的地方都需要显式的设置,必须小于等于最大值,如果不设置报错,如果设置比最大值还大,缓存不生效。

     B. 绝对过期时间(SetAbsoluteExpiration方法和AbsoluteExpiration属性):绝对指的是到了这个时间就过期,不管这期间有没有人访问。

     绝对过期有两种设置方式:① 通过TimeSpan设置距离当前时间的间隔 ② 通过DateTimeOffset设置具体到某一时刻。 详见下面案例④

     C. 滑动过期时间(SetSlidingExpiration方法和SlidingExpiration属性):相对是指以最后一次访问来计算,每访问一次重新计算过期时间。

     D. 缓存级别(SetPriority方法和Priority属性):有Low、Normal、High、NeverRemove。

     E. 缓存移除时回调(RegisterPostEvictionCallback方法和属性):缓存过期或者手动移除时调用,该方法有四个参数,调用的时候自动赋值,分别是: 键、值、消失原因、状态。

     1   {
     2                 string nowTime4 = null;
     3                 if (!_cache2.TryGetValue("t4", out nowTime4))
     4                 {
     5                     nowTime4 = DateTime.Now.ToString();
     6                     MemoryCacheEntryOptions cacheOptions = null;
     7 
     8                     //设置缓存方式一:(通过方法)
     9                     {
    10                         cacheOptions = new MemoryCacheEntryOptions()
    11                          .SetSize(100)
    12                          //.SetSlidingExpiration(TimeSpan.FromSeconds(5))
    13                          //绝对和滑动只能设置一个
    14                          .SetAbsoluteExpiration(TimeSpan.FromSeconds(60))
    15                          .SetPriority(CacheItemPriority.Normal)
    16                          .RegisterPostEvictionCallback(MyCallback, this);
    17 
    18                     }
    19 
    20                     //设置缓存方式二:(通过属性)
    21                     //{
    22                     //    cacheOptions = new MemoryCacheEntryOptions();
    23                     //    cacheOptions.Size = 100;
    24                     //    //cacheOptions.SlidingExpiration = TimeSpan.FromSeconds(5);
    25                     //    //绝对和滑动只能设置一个
    26                     //    cacheOptions.AbsoluteExpiration = new DateTimeOffset(DateTime.Parse("2019-07-16 16:33:10"));
    27                     //    cacheOptions.Priority = CacheItemPriority.High;
    28                     //    cacheOptions.RegisterPostEvictionCallback(MyCallback, this);
    29                     //}
    30                     _cache2.Set("t4", nowTime4, cacheOptions);
    31 
    32                 }
    33                 ViewBag.t4 = nowTime4;
    34             } 
    35 
    36         /// <summary>
    37         /// 失败回调
    38         /// </summary>
    39         /// <param name="key"></param>
    40         /// <param name="value"></param>
    41         /// <param name="reason">缓存消失的原因,比如移除、过期,是个枚举类型</param>
    42         /// <param name="state"></param>
    43         private static void MyCallback(object key, object value, EvictionReason reason, object state)
    44         {
    45             var message = $"Cache entry was removed : key={key},value={value}, reason={reason}, state={state}";
    46         }

    (5) ICacheEntry

     通过属性的形式设置:缓存大小、绝对过期、滑动过期、缓存级别、缓存移除回调,详见案例③

    5.即时创建调用 VS 全局单例调用

     首先需要明白,不管即时创建调用还是全局单例调用,MemoryCache都是存在服务器内存中的,这一点是毋庸置疑的。

     (1) 即时创建调用:多个客户端每次访问该方法的时候,都需要现创建一个IMemoryCache对象,然后进行读取或写入。

     (2) 全局单例调用:只要有一个客户端访问该方法,创建IMemoryCache对象,后续不管谁访问,都是使用的同一个对象进行读取或写入。

     

    很傻瓜的一个问题:内存缓存是以键值对的形式进行存储,同一个键如果多次设置会覆盖,但是不同键之间设置过期时间是互相不影响的。

    !

    • 作       者 : Yaopengfei(姚鹏飞)
    • 博客地址 : http://www.cnblogs.com/yaopengfei/
    • 声     明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
    • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
     
  • 相关阅读:
    如何将网格式报表打印成其它样式
    拥有与实力不相称的脾气是种灾难——北漂18年(23)
    8.8.1 Optimizing Queries with EXPLAIN
    mysql 没有rowid 怎么实现根据rowid回表呢?
    secondary index
    8.5.5 Bulk Data Loading for InnoDB Tables 批量数据加载
    mysql 中key 指的是索引
    8.5.4 Optimizing InnoDB Redo Logging 优化InnoDB Redo 日志
    8.5.3 Optimizing InnoDB Read-Only Transactions 优化InnoDB 只读事务
    8.5.1 Optimizing Storage Layout for InnoDB Tables InnoDB表的存储布局优化
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/11043337.html
Copyright © 2011-2022 走看看