前提:在框架设计中,因为权限菜单访问比较频繁,相对稳定,且数据体积较小,通过缓存来提升性能,提升获取数据的效率。
1.ICache封装
缓存接口,实现对缓存增删改查的封装
1 public interface ICache 2 { 3 /// <summary> 4 /// 读取缓存 5 /// </summary> 6 /// <typeparam name="T"></typeparam> 7 /// <param name="key"></param> 8 /// <returns></returns> 9 T Get<T>(string key); 10 /// <summary> 11 /// 设置缓存 12 /// </summary> 13 /// <param name="key"></param> 14 /// <param name="data"></param> 15 /// <param name="cachetime"></param> 16 void Add<T>(string key, T data, ObsloteType obsloteType = default, int cachetime = 30); 17 /// <summary> 18 /// 是否包含 19 /// </summary> 20 /// <param name="key"></param> 21 /// <returns></returns> 22 bool Contains(string key); 23 /// <summary> 24 /// 清除缓存 25 /// </summary> 26 /// <param name="key"></param> 27 bool Remove(string key); 28 /// <summary> 29 /// 更新缓存 30 /// </summary> 31 /// <param name="key"></param> 32 /// <returns></returns> 33 bool Upate<T>(string key,T data, ObsloteType obsloteType = default, int cacheMin = 30); 34 35 }
枚举类 ObsloteType
1 /// <summary> 2 /// Cache策略类型 永久/绝对过期/滑动过期 3 /// </summary> 4 public enum ObsloteType 5 { 6 /// <summary> 7 /// 永久 8 /// </summary> 9 Never, 10 /// <summary> 11 /// 绝对过期 12 /// </summary> 13 Absolutely, 14 /// <summary> 15 /// 滑动过期 如果期间查询或更新,就再次延长 16 /// </summary> 17 Relative 18 }
2.MemoryCache使用
引用Nuget包 Install-Package Microsoft.Extensions.Caching.Memory
(1)缓存设置
在Startup.cs的ConfigureServices中添加
1 services.AddMemoryCache(options => 2 { 3 //最大缓存空间大小限制为 1024 4 options.SizeLimit = 1024; 5 //缓存策略设置为缓存压缩比为 2% 6 options.CompactionPercentage = 0.02d; 7 //每 5 分钟进行一次过期缓存的扫描 8 options.ExpirationScanFrequency = TimeSpan.FromMinutes(5); 9 });
(2)注入并使用
1 private readonly IMemoryCache _memoryCache; 2 public HomeController(IMemoryCache memoryCache) 3 { 4 _memoryCache = memoryCache; 5 }
缓存的操作增删改查
(2-1)Set
public IActionResult Index() { _memoryCache.Set<string>("timestamp", DateTime.Now.ToString()); return View(); }
(2-2)Get
public IActionResult Show() { string timestamp = _memoryCache.Get<string>("timestamp"); return View("Show",timestamp); }
(2-3)TryGetValue检查特定值
if (!_memoryCache.TryGetValue<string> ("timestamp", out string timestamp)) { _memoryCache.Set<string>("timestamp", DateTime.Now.ToString()); }
(2-4)GetOrCreate() 不存在新增,存在获取
public IActionResult Show() { string timestamp = cache.GetOrCreate<string> ("timestamp", entry => { return DateTime.Now.ToString(); }); return View("Show",timestamp); }
缓存的过期时间策略: 永久|绝对过期|滚动过期
(2-5)缓存时间配置
绝对过期:AbsoluteExpiration 在指定的日期和时间点被移除
滚动过期: SlidingExpiration 在一段时间内处于空闲状态会被移除
1 MemoryCacheEntryOptions options = new MemoryCacheEntryOptions(); 2 options.AbsoluteExpiration = DateTime.Now.AddMinutes(1); 3 options.SlidingExpiration = TimeSpan.FromMinutes(1); 4 _memoryCache.Set<string>("timestamp", DateTime.Now.ToString(), options);
2.扩展MemoryEetensions
(1)新建“MemoryCacheExtensions”实现ICache的接口
1 public class MemoryCacheExtensions:ICache 2 { 3 private readonly IMemoryCache _cache; 4 /// <summary> 5 /// 缓存配置项 6 /// </summary> 7 private readonly MemoryCacheEntryOptions _memoryCacheEntryOptions; 8 //构造器注入 9 public MemoryCacheExtensions(IMemoryCache cache) 10 { 11 //单项缓存设置项 12 _memoryCacheEntryOptions = new MemoryCacheEntryOptions() 13 { 14 Priority = CacheItemPriority.Low, 15 //缓存大小占1份 16 Size = 1 17 }; 18 _cache = cache; 19 } 20 /// <summary> 21 /// 添加 22 /// </summary> 23 /// <param name="key"></param> 24 /// <param name="data"></param> 25 /// <param name="cacheMin"></param> 26 /// <param name="obsloteType"></param> 27 public void Add<T>(string key, T data, ObsloteType obsloteType = default, int cacheMin = 30) 28 { 29 if (obsloteType == ObsloteType.Absolutely) 30 { 31 _memoryCacheEntryOptions.AbsoluteExpiration = DateTime.Now.AddMinutes(cacheMin); 32 } 33 if (obsloteType == ObsloteType.Relative) 34 { 35 _memoryCacheEntryOptions.SlidingExpiration = TimeSpan.FromMinutes(cacheMin); 36 } 37 if (Contains(key)) 38 { 39 Upate<T>(key, data, obsloteType); 40 } 41 else 42 { 43 _cache.Set(key, data, _memoryCacheEntryOptions); 44 } 45 46 } 47 /// <summary> 48 /// 是否存在 49 /// </summary> 50 /// <param name="key"></param> 51 /// <returns></returns> 52 public bool Contains(string key) 53 { 54 object RetValue; 55 return _cache.TryGetValue(key, out RetValue); 56 } 57 public T Get<T>(string key) 58 { 59 return _cache.Get<T>(key); 60 } 61 62 public bool Remove(string key) 63 { 64 bool ReturnBool = true; 65 if (!Contains(key)) 66 { 67 ReturnBool = false; 68 } 69 else { 70 _cache.Remove(key); 71 } 72 73 return ReturnBool; 74 } 75 public bool Upate<T>(string key,T data, ObsloteType obsloteType, int cacheMin = 30) 76 { 77 bool ReturnBool = true; 78 if (!Contains(key)) 79 { 80 ReturnBool = false; 81 } 82 else 83 { 84 _cache.Remove(key); 85 Add(key, data, obsloteType, cacheMin); 86 } 87 return ReturnBool; 88 89 } 90 }
其中“MemoryCacheEntryOptions”缓存项设置,可以设置Priority(优先级),Size(缓存大小),缓存时间的配置(参见2-5)
(2)在Startup中注入扩展类
services.AddScoped(typeof(MemoryCacheExtensions));
3.MemoryCacheExtensions使用,对权限菜单缓存读取
1 private readonly Frame_RelationsService _service; 2 private readonly MemoryCacheExtensions _memoryCacheExtensions; 3 public FrameRelationsController(Frame_RelationsService service, MemoryCacheExtensions memoryCacheExtensions) 4 { 5 _service = service; 6 _memoryCacheExtensions = memoryCacheExtensions; 7 } 8 9 [AllowAnonymous] 10 public string LoadRoleMenu( ) 11 { 12 PageResponse resp = new PageResponse(); 13 string KeyName = "Menu_" + CurrentUser.ID; 14 //第一次加载 判断是否有Key为"Keyname"的缓存 15 if (_memoryCacheExtensions.Contains(KeyName)) 16 { 17 resp.Message = _memoryCacheExtensions.Get<string>(KeyName); 18 } 19 else 20 { 21 //返回菜单权限的信息 22 resp.Message = _service.LoadRoleMenu(CurrentUser.RoleID); 23 _memoryCacheExtensions.Add<string>(KeyName, resp.Message); 24 } 25 return JsonHelper.Instance.Serialize(Newtonsoft.Json.Linq.JArray.Parse(resp.Message)); 26 }
总结:适合缓存的特点:访问频繁,耗时耗资源,相对稳定,体积不大。
举例:字典/省市区/配置文件/公告信息/部门/权限/热搜/产品列表/商品评论