关于我

作者博客|文章首发

缓存基础知识

缓存可以减少生成内容所需的工作,从而显著提高应用程序的性能和可伸缩性。 缓存最适用于不经常更改的 数据,生成 成本很高。 通过缓存,可以比从数据源返回的数据的副本速度快得多。 应该对应用进行编写和测试,使其 永不 依赖于缓存的数据。

ASP.NET Core 支持多个不同的缓存。 最简单的缓存基于 IMemoryCache。 IMemoryCache 表示存储在 web 服务器的内存中的缓存。 在服务器场上运行的应用 (多台服务器) 应确保会话在使用内存中缓存时处于粘滞状态。 粘滞会话确保来自客户端的后续请求都将发送到相同的服务器。

内存中缓存可以存储任何对象。 分布式缓存接口仅限 byte[] 。 内存中和分布式缓存将缓存项作为键值对。

缓存指南

  • 代码应始终具有回退选项,以获取数据,而 是依赖于可用的缓存值。
  • 缓存使用稀有资源内存,限制缓存增长:
    • 不要 使用外部 输入作为缓存键。
    • 使用过期限制缓存增长。
    • 使用 SetSize、Size 和 SizeLimit 限制缓存大小]。 ASP.NET Core 运行时不会根据内存 压力限制缓存 大小。 开发人员需要限制缓存大小。

使用

DI注入

创建一个NetCore控制台项目,进行缓存的项目演示。

控制台项目只有一个初始化的Program.cs文件。基于NetCore进行项目编码,每一步就是创建一个基础模板,使用依赖注入的方式。

nuget install Microsoft.Extensions.Hosting
  public static class Program
{
static async void Main(string[] args)
{
var builder = new HostBuilder().ConfigureServices((context, service) =>
{ }); await builder.RunConsoleAsync();
}
}

注入缓存服务,控制台需要下载库 Microsoft.Extensions.Caching.Memory

nuget install Microsoft.Extensions.Caching.Memory
  public static class Program
{
static async void Main(string[] args)
{
var builder = new HostBuilder().ConfigureServices((context, service) =>
{
service.AddMemoryCache(); service.AddScoped<CacheService>();//实际测试服务 service.AddHostedService<BackgroundJob>();//后台执行方法
}); await builder.RunConsoleAsync();
}
}

后台服务

public class BackgroundJob : IHostedService
{
private readonly CacheService _cacheService; public BackgroundJob(CacheService cacheService)
{
_cacheService = cacheService;
} public Task StartAsync(CancellationToken cancellationToken)
{
_cacheService.Action(); return Task.CompletedTask;
} public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}

MemoryCache使用总结

通过构造函数自动注入IMemoryCache

public class CacheService
{
private readonly IMemoryCache _memoryCache; public CacheService(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
}

最基本的使用

Set方法根据Key设置缓存,默认缓存不过期

Get方法根据Key取出缓存

/// <summary>
/// 缓存设置
/// </summary>
public void BaseCache()
{
string cacheKey = "timestamp";
//set cache
_memoryCache.Set(cacheKey, DateTime.Now.ToString()); //get cache
Console.WriteLine(_memoryCache.Get(cacheKey));
}

IMemoryCache提供一些好的语法糖供开发者使用,具体内容看下方文档

/// <summary>
/// 特殊方法的使用
/// </summary>
public void ActionUse()
{
//场景-如果缓存存在,取出。如果缓存不存在,写入
//原始写法
string cacheKey = "timestamp";
if (_memoryCache.Get(cacheKey) != null)
{
_memoryCache.Set(cacheKey, DateTime.Now.ToString());
}
else
{
Console.WriteLine(_memoryCache.Get(cacheKey));
} //新写法
var dataCacheValue = _memoryCache.GetOrCreate(cacheKey, entry =>
{
return DateTime.Now.ToString();
});
Console.WriteLine(dataCacheValue); //删除缓存
_memoryCache.Remove(cacheKey); //场景 判断缓存是否存在的同时取出缓存数据
_memoryCache.TryGetValue(cacheKey, out string cacheValue);
Console.WriteLine(cacheValue); }

缓存过期策略

设置缓存常用的方式主要是以下二种

  1. 绝对到期(指定在一个固定的时间点到期)
  2. 滑动到期(在一个时间长度内没有被命中则过期)
  3. 组合过期 (绝对过期+滑动过期)

绝对到期

过期策略 5秒后过期

//set absolute cache
string cacheKey = "absoluteKey";
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), TimeSpan.FromSeconds(5)); //get absolute cache
for (int i = 0; i < 6; i++)
{
Console.WriteLine(_memoryCache.Get(cacheKey));
Thread.Sleep(1000);
}

滑动到期

过期策略 2秒的滑动过期时间,如果2秒内有访问,过期时间延后。当2秒的区间内没有访问,缓存过期

//set slibing cache
string cacheSlibingKey = "slibingKey";
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.SlidingExpiration = TimeSpan.FromSeconds(2); _memoryCache.Set(cacheSlibingKey, DateTime.Now.ToString(), options); //get slibing cache
for (int i = 0; i < 2; i++)
{
Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
Thread.Sleep(1000);
}
for (int i = 0; i < 2; i++)
{
Thread.Sleep(2000);
Console.WriteLine(_memoryCache.Get(cacheSlibingKey));
}

组合过期

过期策略

6秒绝对过期+2秒滑动过期

满足任意一个缓存都将失效

string cacheCombineKey = "combineKey";
MemoryCacheEntryOptions combineOptions = new MemoryCacheEntryOptions();
combineOptions.SlidingExpiration = TimeSpan.FromSeconds(2);
combineOptions.AbsoluteExpiration = DateTime.Now.AddSeconds(6); _memoryCache.Set(cacheCombineKey, DateTime.Now.ToString(), combineOptions); //get slibing cache
for (int i = 0; i < 2; i++)
{
Console.WriteLine(_memoryCache.Get(cacheCombineKey));
Thread.Sleep(1000);
} for (int i = 0; i < 6; i++)
{
Thread.Sleep(2000);
Console.WriteLine(i+"|" + _memoryCache.Get(cacheCombineKey));
} Console.WriteLine("------------combineKey End----------------");

缓存状态变化事件

当缓存更新、删除时触发一个回调事件,记录缓存变化的内容。

/// <summary>
/// cache状态变化回调
/// </summary>
public void CacheStateCallback()
{
MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.AbsoluteExpiration = DateTime.Now.AddSeconds(3
);
options.RegisterPostEvictionCallback(MyCallback, this); //show callback console
string cacheKey = "absoluteKey";
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); Thread.Sleep(500);
_memoryCache.Set(cacheKey, DateTime.Now.ToString(), options); _memoryCache.Remove(cacheKey); } private static void MyCallback(object key, object value, EvictionReason reason, object state)
{
var message = $"Cache entry state change:{key} {value} {reason} {state}";
((CacheService)state)._memoryCache.Set("callbackMessage", message); Console.WriteLine(message);
}

缓存依赖策略

设置一个缓存A

设置一个缓存B,依赖于缓存A 如果缓存A失效,缓存B也失效

/// <summary>
/// 缓存依赖策略
/// </summary>
public void CacheDependencyPolicy()
{
string DependentCTS = "DependentCTS";
string cacheKeyParent = "CacheKeys.Parent";
string cacheKeyChild = "CacheKeys.Child"; var cts = new CancellationTokenSource();
_memoryCache.Set(DependentCTS, cts); //创建一个cache策略
using (var entry = _memoryCache.CreateEntry(cacheKeyParent))
{
//当前key对应的值
entry.Value = "parent" + DateTime.Now; //当前key对应的回调事件
entry.RegisterPostEvictionCallback(MyCallback, this); //基于些key创建一个依赖缓存
_memoryCache.Set(cacheKeyChild, "child" + DateTime.Now, new CancellationChangeToken(cts.Token));
} string ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent);
string ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild);
string callBackMsg = _memoryCache.Get<string>("callbackMessage");
Console.WriteLine("第一次获取");
Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg); //移除parentKey
_memoryCache.Get<CancellationTokenSource>(DependentCTS).Cancel();
Thread.Sleep(1000); ParentCachedTime = _memoryCache.Get<string>(cacheKeyParent);
ChildCachedTime = _memoryCache.Get<string>(cacheKeyChild);
callBackMsg = _memoryCache.Get<string>("callbackMessage");
Console.WriteLine("第二次获取");
Console.WriteLine(ParentCachedTime + "|" + ChildCachedTime + "|" + callBackMsg);
}

参考资料

AspNetCore中的缓存内存

.NetCore缓存篇之MemoryCache

Asp.Net Core 轻松学-在.Net Core 使用缓存和配置依赖策略

拥抱.NET Core系列:MemoryCache 缓存过期

推荐阅读

Redis工具收费后新的开源已出现

GitHub上Star最高的工程师技能图谱

中国程序员最容易发错的单词

推荐!!! Markdown图标索引网站

最后

本文到此结束,希望对你有帮助

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

更多精彩技术文章汇总在我的 公众号【程序员工具集】,持续更新,欢迎关注订阅收藏。

NetCore的缓存使用详例的更多相关文章

  1. Redis for Windows(C#缓存)配置文件详解

    Redis for Windows(C#缓存)配置文件详解   前言 在上一篇文章中主要介绍了Redis在Windows平台下的下载安装和简单使用http://www.cnblogs.com/aehy ...

  2. 《深入理解mybatis原理6》 MyBatis的一级缓存实现详解 及使用注意事项

    <深入理解mybatis原理> MyBatis的一级缓存实现详解 及使用注意事项 0.写在前面   MyBatis是一个简单,小巧但功能非常强大的ORM开源框架,它的功能强大也体现在它的缓 ...

  3. 浏览器 HTTP 协议缓存机制详解

    最近在准备优化日志请求时遇到了一些令人疑惑的问题,比如为什么响应头里出现了两个 cache control.为什么明明设置了 no cache 却还是发请求,为什么多次访问时有时请求里带了 etag, ...

  4. nginx平台初识(二) 浏览器 HTTP 协议缓存机制详解

    1.缓存的分类 缓存分为服务端侧(server side,比如 Nginx.Apache)和客户端侧(client side,比如 web browser). 服务端缓存又分为 代理服务器缓存 和 反 ...

  5. PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

  6. 二,PHP缓存机制详解

    一,PHP缓存机制详解 我们可以使用PHP自带的缓存机制来完成页面静态化,但是仅靠PHP自身的缓存机制并不能完美的解决页面静态化,往往需要和其他静态化技术(通常是伪静态技术)结合使用. output ...

  7. hibernate缓存机制详解

    hiberante面试题—hibernate缓存机制详解   这是面试中经常问到的一个问题,可以按照我的思路回答,准你回答得很完美.首先说下Hibernate缓存的作用(即为什么要用缓存机制),然后再 ...

  8. Robocopy.exe使用详例

    Robocopy.exe使用详例           Robocopy.exe 是 微软在Windows server 2003 Resource Kit Tools 里面提供的程序来做备份的.Vis ...

  9. 浏览器 HTTP 协议缓存机制详解--网络缓存决策机制流程图

    1.缓存的分类 2.浏览器缓存机制详解 2.1 HTML Meta标签控制缓存 2.2 HTTP头信息控制缓存 2.2.1 浏览器请求流程 2.2.2 几个重要概念解释 3.用户行为与缓存 4.Ref ...

随机推荐

  1. window.URL.createObjectURL

    window.URL.createObjectURL https://html5.xgqfrms.xyz/Canvas/safety-canvas.html var video = document. ...

  2. Excel和CSV格式文件的不同之处

    来源:https://blog.csdn.net/weixin_39198406/article/details/78705016 1.个人理解:为何选择使用csv来存储接口测试用例相关字段数据,而不 ...

  3. MapReduce原理及简单实现

    MapReduce是Google在2004年发表的论文<MapReduce: Simplified Data Processing on Large Clusters>中提出的一个用于分布 ...

  4. requests页面请求返回400:{"errors":{"username":"值必须是非空字符串。"}}

    我的描述:我引入requests包,携带json类型数据请求(POST)一个网站,,访问提示<Response [400]> 解决方案: 1.首先使用postman请求一模一样的数据,发现 ...

  5. PriorityQueue使用介绍

    这玩意儿叫优先级队列,是一个类,继承了AbstractQueue类,实现了Serializable接口. jdk文档里是这么描述这玩意的: 基于优先级堆的无限优先级queue . 优先级队列的元素根据 ...

  6. 你真的懂 MP4 格式吗?

    MP4 文件格式又被称为 MPEG-4 Part 14,出自 MPEG-4 标准第 14 部分 .它是一种多媒体格式容器,广泛用于包装视频和音频数据流.海报.字幕和元数据等.(顺便一提,目前流行的视频 ...

  7. oracle数据库date类型和mysql数据库datetime类型匹配

    oracle数据库有date类型,但是没有datetime类型 mysql数据库既有date类型也有datetime类型. Oracle数据库的date类型和mysql的date类型是不一样的,Ora ...

  8. java与freemarker遍历map

    一.java遍历MAP /** * 1.把key放到一个集合里,遍历key值同时根据key得到值 (推荐) */ Set set =map.keySet(); Iterator it=set.iter ...

  9. 一文了解python的 @property

    参考自: https://www.programiz.com/python-programming/property Python为我们提供了一个内置装饰器@property,此方法使得getter和 ...

  10. QQ 邀你上线小程序,官方生态能力持续赋能你的小程序

    转: QQ 邀你上线小程序,官方生态能力持续赋能你的小程序 你身边总有一些朋友,他们的表情包极其丰富,能时刻应对各种聊天场景. 表情包奇奇怪怪,可可爱爱,非常形象生动体现我们当下的心情,逐渐成为社交平 ...