.NET Core缓存

目录

缓存的概念

客户端响应缓存

cache-control

服务器端响应缓存

内存缓存(In-memory cache)

用法

GetOrCreateAsync

缓存过期时间策略

缓存的过期时间

解决方法:

两种过期时间策略:

绝对过期时间

滑动过期时间

两种过期时间混用

总结

 封装内存缓存操作的帮助类

使用


缓存的概念

缓存(Caching)是用来保存数据的区域,从缓存区域读取数据的速度比从数据源读取数据的速度快很多,从数据源获取数据后,我们可以把数据保存到缓存中,下次再需要获取同样数据时,可以直接从缓存中获取之前保存的数据,是系统优化中简单又有效的工具,投入小收效大。数据库中的索引等简单有效的优化功能本质上都是缓存。

  1. 缓存命中:从缓存中获取了要获取的数据
  2. 缓存命中率:多次请求中,命中的请求占全部请求的百分比
  3. 缓存数据不一致:数据源中数据保存到缓存后,发生了变化
  4. 多级缓存:在Web开发中,存在多级缓存,浏览器存在“浏览器端缓存”,网关节电服务器存在“节点缓存”,,Web服务器上可能存在“服务器端缓存”,只要在任何一个节点上命中缓存,请求就会直接返回,而不会继续向后传递。

客户端响应缓存

cache-control

  1. RFC7324是HTTP协议中对缓存进行控制的规范,其中重要的是cache-control这个响应报文头。服务器如果返回cache-control:max-age=60,则表示服务器指示浏览器端“可以缓存这个响应内容60秒”。
  2. 我们只要给需要进行缓存控制的控制器的操作方法添加ResponseCacheAttribute这个Attribute,ASP.NET Core会自动添加cache-control报文头。
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{[HttpGet][ResponseCache(Duration = 20)]public DateTime Now(){return DateTime.Now;}
}

服务器端响应缓存

  1. 如果ASP.NET Core中安装了“响应缓存中间件” ,那么ASP.NET Core不仅会继续根据[ResponseCache]设置来生成cache-control响应报文头来设置客户端缓存,而且服务器端也会按照[ResponseCache]的设置来对响应进行服务器端缓存。和客户端端缓存的区别?来自多个不同客户端的相同请求。
  2. “响应缓存中间件”的好处:对于来自不同客户端的相同请求或者不支持客户端缓存的客户端,能降低服务器端的压力。
  3. 用法:app.MapControllers()之前加上app.UseResponseCaching()。请确保app.UseCors()写到app.UseResponseCaching()之前。

缺点:

  1. 无法解决恶意请求给服务器带来的压力。
  2. 服务器端响应缓存还有很多限制,包括但不限于:响应状态码为200的GET或者HEAD响应才可能被缓存;报文头中不能含有Authorization、Set-Cookie等。
  3. 可以采用内存缓存、分布式缓存等。

由于服务器端响应缓存开发调试的麻烦以及过于苛刻的限制,因此除非开发人员能够灵活掌握并应用,否则不建议启用“响应缓存中间件”。对于只需要进行客户端响应缓存处理的操作方法,标注ResponseCache即可,如果还需要在服务器端进行缓存处理,建议采用ASP.NET Core提供的内存缓存、分布式缓存等机制来编写程序。

内存缓存(In-memory cache)

把缓存数据放到应用程序的内存。内存缓存中保存的是一系列的键值对,就像Dictionary类型一样。

内存缓存的数据保存在当前运行的网站程序的内存中,是和进程相关的。因为在Web服务器中,多个不同网站是运行在不同的进程中的,因此不同网站的内存缓存是不会互相干扰的,而且网站重启后,内存缓存中的所有数据也就都被清空了。

用法

  1. 添加服务:builder.Services.AddMemoryCache()
  2. 注入IMemoryCache接口,查看接口的方法:TryGetValue、Remove、Set、GetOrCreate、GetOrCreateAsync

GetOrCreateAsync

GetOrCreateAsync<TItem>(object key, Func<ICacheEntry, Task<TItem>> factory)

获取缓存键为key的缓存值,方法的返回值为获取的缓存值,如果缓存中没有缓存键为key的缓存值,则调用factory指向的回调从数据源获取数据,把获取的数据作为缓存值保存到缓存中,并且把获取的数据作为方法的返回值。

Program.cs
//添加内存缓存服务
services.AddMemoryCache();
//添加DbContext
services.AddScoped<MyDbContext>();public record Book(long Id, string Name);public class BookConfig : IEntityTypeConfiguration<Book>
{public void Configure(EntityTypeBuilder<Book> builder){builder.ToTable("T_Books");}
}public class MyDbContext:DbContext
{DbSet<Book> books {  get; set; }protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){base.OnConfiguring(optionsBuilder);optionsBuilder.UseSqlServer("Server=.;Database=demo;Trusted_Connection=true;MultipleActiveResultSets=true;TrustServerCertificate=true;");}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);}
}
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{private readonly IMemoryCache memoryCache;private readonly ILogger<TestController> logger;public TestController(IMemoryCache memoryCache, ILogger<TestController> logger){this.memoryCache = memoryCache;this.logger = logger;}[HttpGet]public async Task<ActionResult<Book?>> GetById(int id){using (MyDbContext ctx = new MyDbContext()){//没加内存缓存//var result = await ctx.Set<Book>().SingleOrDefaultAsync(o => o.Id == id);//if (result == null)//{//    return NotFound($"找不到id={id}的书");//}//else//{//    return result;//}//内存缓存logger.LogInformation($"开始执行GetBookById,id={id}");Book? b = await memoryCache.GetOrCreateAsync("Book" + id, async (e) =>{logger.LogInformation($"缓存没找到,到数据库查询,id={id}");return await ctx.Set<Book>().SingleOrDefaultAsync(o => o.Id == id);});logger.LogInformation($"GetBookById结果:{b}");if (b == null){return NotFound($"找不到id={id}的书");}else{return Ok(b);}}}
}

 查询两次结果

缓存过期时间策略

缓存的过期时间

上面的例子中的缓存不会过期,除非重启服务器。

解决方法:

  1. 在数据改变的时候调用Remove或者Set来删除或者修改缓存(优点:及时);
  2. 过期时间(只要过期时间比较短,缓存数据不一致的情况也不会持续很长时间。)

两种过期时间策略:

GetOrCreateAsync()方法的回调方法中有一个ICacheEntry类型的参数,通过ICacheEntry对当前的缓存项做设置。

绝对过期时间

设置缓存完的指定时间后,缓存项被清除。

AbsoluteExpirationRelativeToNow:用来设定缓存项的绝对过期时间。

Book? b = await memoryCache.GetOrCreateAsync("Book" + id, async (e) =>
{logger.LogInformation($"缓存没找到,到数据库查询,id={id}");//缓存有效期10se.AbsoluteExpirationRelativeToNow=TimeSpan.FromSeconds(10);return await ctx.Set<Book>().SingleOrDefaultAsync(o => o.Id == id);
});
滑动过期时间

设置缓存完的指定时间后,如果对应的缓存数据没有被访问,缓存项被清除,如果在指定时间内,被访问一次,则缓存项的过期时间会自动续期。

Book? b = await memoryCache.GetOrCreateAsync("Book" + id, async (e) =>
{logger.LogInformation($"缓存没找到,到数据库查询,id={id}");e.SlidingExpiration=TimeSpan.FromSeconds(10);return await ctx.Set<Book>().SingleOrDefaultAsync(o => o.Id == id);
});
两种过期时间混用

使用滑动过期时间策略,如果一个缓存项一直被频繁访问,那么这个缓存项就会一直被续期而不过期。可以对一个缓存项同时设定滑动过期时间和绝对过期时间,并且把绝对过期时间设定的比滑动过期时间长,这样缓存项的内容会在绝对过期时间内随着访问被滑动续期,但是一旦超过了绝对过期时间,缓存项就会被删除。

总结

  1. 无论用那种过期时间策略,程序中都会存在缓存数据不一致的情况。部分系统(博客等)无所谓,部分系统不能忍受(比如金融)。
  2. 可以通过其他机制获取数据源改变的消息,再通过代码调用IMemoryCache的Set方法更新缓存。

 封装内存缓存操作的帮助类

  1. IQueryable、IEnumerable等类型可能存在着延迟加载的问题,如果把这两种类型的变量指向的对象保存到缓存中,在我们把它们取出来再去执行的时候,如果它们延迟加载时候需要的对象已经被释放的话,就会执行失败。因此缓存禁止这两种类型。
  2. 实现随机缓存过期时间

使用

Install-Package Zack.ASPNETCore
NETBookMaterials/最后大项目代码/YouZack-VNext/Zack.ASPNETCore/MemoryCacheHelper.cs at main · yangzhongke/NETBookMaterialshttps://github.com/yangzhongke/NETBookMaterials/blob/main/%E6%9C%80%E5%90%8E%E5%A4%A7%E9%A1%B9%E7%9B%AE%E4%BB%A3%E7%A0%81/YouZack-VNext/Zack.ASPNETCore/MemoryCacheHelper.cshttps://github.com/yangzhongke/NETBookMaterials/blob/main/%E6%9C%80%E5%90%8E%E5%A4%A7%E9%A1%B9%E7%9B%AE%E4%BB%A3%E7%A0%81/YouZack-VNext/Zack.ASPNETCore/MemoryCacheHelper.cshttps://github.com/yangzhongke/NETBookMaterials/blob/main/%E6%9C%80%E5%90%8E%E5%A4%A7%E9%A1%B9%E7%9B%AE%E4%BB%A3%E7%A0%81/YouZack-VNext/Zack.ASPNETCore/MemoryCacheHelper.cshttps://github.com/yangzhongke/NETBookMaterials/blob/main/%E6%9C%80%E5%90%8E%E5%A4%A7%E9%A1%B9%E7%9B%AE%E4%BB%A3%E7%A0%81/YouZack-VNext/Zack.ASPNETCore/MemoryCacheHelper.cs

services.AddMemoryCache();
services.AddScoped<IMemoryCacheHelper,MemoryCacheHelper>();public TestController(IMemoryCache memoryCache, MyDbContext ctx, MemoryCacheHelper memoryCacheHelper)
{this.memoryCache = memoryCache;this.ctx = ctx;this.memoryCacheHelper = memoryCacheHelper;
}[HttpGet]
public async Task<ActionResult<Book?>> Test(long id)
{var b = memoryCacheHelper.GetOrCreateAsync("Book" + id, async (e) =>{return await ctx.Set<Book>().SingleOrDefaultAsync(o => o.Id == id);}, 10);if (b.Result == null){return NotFound("不存在");}else{return Ok(b.Result);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/10208.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++,STL 六大组件:容器、迭代器、算法、函数对象、适配器、分配器

文章目录 引言一、容器&#xff08;Containers&#xff09;主要分类 二、迭代器&#xff08;Iterators&#xff09;三、算法&#xff08;Algorithms&#xff09;四、函数对象&#xff08;Functors&#xff09;五、适配器&#xff08;Adapters&#xff09;六、分配器&#xff08…

996引擎 - NPC-添加NPC引擎自带形象

996引擎 - NPC-添加NPC引擎自带形象 截图参考添加NPC参考资料截图参考 添加NPC 编辑NPC表:Envir\DATA\cfg_npclist.xls 1.1. 需要临时隐藏NPC时可以在id前加 // 1.2. 如果NPC朝向不对,可以调整dir 列。(按8方向,上是0顺时针数。我这里给的4) 1.3. 形象代码:NPC代码、怪物…

【懒删除堆】力扣2349. 设计数字容器系统

设计一个数字容器系统&#xff0c;可以实现以下功能&#xff1a; 在系统中给定下标处 插入 或者 替换 一个数字。 返回 系统中给定数字的最小下标。 请你实现一个 NumberContainers 类&#xff1a; NumberContainers() 初始化数字容器系统。 void change(int index, int numb…

利用飞书机器人进行 - ArXiv自动化检索推荐

相关作者的Github仓库 ArXivToday-Lark 使用教程 Step1 新建机器人 根据飞书官方机器人使用手册&#xff0c;新建自定义机器人&#xff0c;并记录好webhook地址&#xff0c;后续将在配置文件中更新该地址。 可以先完成到后续步骤之前&#xff0c;后续的步骤与安全相关&…

SpringBoot 日志

目录 一. 日志概述 二. 日志的使用 1. 打印日志 (1) 获取日志对象 (2) 输出要打印的内容 2. 日志框架简介 (1) 门面模式简介 (2) SLF4J 框架简介 3. 日志的格式 4. 日志的级别 5. 日志配置 (1) 配置日志级别 (2) 日志持久化存储 ① 配置日志文件名 ② 配置日志的…

RK3568中使用QT opencv(显示基础图像)

文章目录 一、查看对应的开发环境是否有opencv的库二、QT使用opencv 一、查看对应的开发环境是否有opencv的库 在开发板中的/usr/lib目录下查看是否有opencv的库&#xff1a; 这里使用的是正点原子的ubuntu虚拟机&#xff0c;在他的虚拟机里面已经安装好了opencv的库。 二、…

LMI Gocator GO_SDK VS2019引用配置

LMI SDK在VS2019中的引用是真的坑爹,总结一下经验,希望后来的人能少走弯路.大致内容如下: &#xff08;1&#xff09; 环境变量 &#xff08;2&#xff09;C/C 附加包含目录 E:\GWQ\Gocator\GO_SDK\Gocator\GoSdk E:\GWQ\Gocator\GO_SDK\Platform\kApi &#xff08;3&#…

模型I/O

文章目录 什么是模型I/O模型I/O功能之输出解析器输出解析器的功能输出解析器的使用Pydantic JSON输出解析器结构化输出解析器 什么是模型I/O 模型I/O在所有LLM应用中&#xff0c;核心元素无疑都是模型本身。与模型进行有效的交互是实现高效、灵活和可扩展应用的关键。LangChain…

C语言练习(31)

有5个学生&#xff0c;每个学生有3门课程的成绩&#xff0c;从键盘输入以上数据&#xff08;包括学号、姓名、3门课程成绩&#xff09;&#xff0c;计算出平均成绩&#xff0c;将原有数据和计算出的平均分数存放在磁盘文件stud中。 设5名学生的学号、姓名和3门课程成绩如下&am…

【Block总结】DynamicFilter,动态滤波器降低计算复杂度,替换传统的MHSA|即插即用

论文信息 标题: FFT-based Dynamic Token Mixer for Vision 论文链接: https://arxiv.org/pdf/2303.03932 关键词: 深度学习、计算机视觉、对象检测、分割 GitHub链接: https://github.com/okojoalg/dfformer 创新点 本论文提出了一种新的标记混合器&#xff08;token mix…

「AI学习笔记」深度学习的起源与发展:从神经网络到大数据(二)

深度学习&#xff08;DL&#xff09;是现代人工智能&#xff08;AI&#xff09;的核心之一&#xff0c;但它并不是一夜之间出现的技术。从最初的理论提出到如今的广泛应用&#xff0c;深度学习经历了几乎一个世纪的不断探索与发展。今天&#xff0c;我们一起回顾深度学习的历史…

Axure PR 9 旋转效果 设计交互

大家好&#xff0c;我是大明同学。 这期内容&#xff0c;我们将学习Axure中的旋转效果设计与交互技巧。 旋转 创建旋转效果所需的元件 1.打开一个新的 RP 文件并在画布上打开 Page 1。 2.在元件库中拖出一个按钮元件。 创建交互 创建按钮交互状态 1.选中按钮元件&#xf…

【外文原版书阅读】《机器学习前置知识》2.用看电影推荐的例子带你深入了解向量点积在机器学习的作用

目录 3.3 Where Are You Looking, Vector? The Dot Product 个人主页&#xff1a;Icomi 大家好&#xff0c;我是Icomi&#xff0c;本专栏是我阅读外文原版书《Before Machine Learning》对于文章中我认为能够增进线性代数与机器学习之间的理解的内容的一个输出&#xff0c;希望…

论文阅读(八):结构方程模型用于研究数量遗传学中的因果表型网络

1.论文链接&#xff1a;Structural Equation Models for Studying Causal Phenotype Networks in Quantitative Genetics 摘要&#xff1a; 表型性状可能在它们之间发挥因果作用。例如&#xff0c;农业物种的高产可能会增加某些疾病的易感性&#xff0c;相反&#xff0c;疾病的…

每日一题——序列化二叉树

序列化二叉树 BM39 序列化二叉树题目描述序列化反序列化 示例示例1示例2 解题思路序列化过程反序列化过程 代码实现代码说明复杂度分析总结 BM39 序列化二叉树 题目描述 请实现两个函数&#xff0c;分别用来序列化和反序列化二叉树。二叉树的序列化是将二叉树按照某种遍历方式…

JVM_程序计数器的作用、特点、线程私有、本地方法的概述

①. 程序计数器 ①. 作用 (是用来存储指向下一条指令的地址,也即将要执行的指令代码。由执行引擎读取下一条指令) ②. 特点(是线程私有的 、不会存在内存溢出) ③. 注意:在物理上实现程序计数器是在寄存器实现的,整个cpu中最快的一个执行单元 ④. 它是唯一一个在java虚拟机规…

Attention--人工智能领域的核心技术

1. Attention 的全称与基本概念 在人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;领域&#xff0c;Attention 机制的全称是 Attention Mechanism&#xff08;注意力机制&#xff09;。它是一种能够动态分配计算资源&#xff0c;使模型在处理输入数据…

机器学习2 (笔记)(朴素贝叶斯,集成学习,KNN和matlab运用)

朴素贝叶斯模型 贝叶斯定理&#xff1a; 常见类型 算法流程 优缺点 集成学习算法 基本原理 常见方法 KNN&#xff08;聚类模型&#xff09; 算法性质&#xff1a; 核心原理&#xff1a; 算法流程 优缺点 matlab中的运用 朴素贝叶斯模型 朴素贝叶斯模型是基于贝叶斯…

智慧园区系统助力企业智能化升级实现管理效率与安全性全方位提升

内容概要 在当今数字化转型的浪潮中&#xff0c;企业面临着前所未有的挑战和机遇。智慧园区系统作为一种创新性解决方案&#xff0c;正在快速崛起&#xff0c;帮助企业实现全面的智能化升级。这套系统不仅仅是一个简单的软件工具&#xff0c;而是一个强大的综合管理平台&#…

【视频+图文详解】HTML基础4-html标签的基本使用

图文教程 html标签的基本使用 无序列表 作用&#xff1a;定义一个没有顺序的列表结构 由两个标签组成&#xff1a;<ul>以及<li>&#xff08;两个标签都属于容器级标签&#xff0c;其中ul只能嵌套li标签&#xff0c;但li标签能嵌套任何标签&#xff0c;甚至ul标…