.NET Core内存缓存的理解和使用以及过期时间策略

4.内存缓存
  • 是什么?

除了响应缓存中间件这样自动化的服务器缓存机制之外,ASP.NET Core还提供了允许开发人员手动进行缓存管理的机制,这就是内存缓存!

内存缓存就是一种把缓存数据放到应用程序内存中的机制,这种缓存是在当前运行的程序内存之中,是和进程相关的。在一个Web服务器中,多个不同的程序是运行在不同的进程中的,所以不同的程序之间的内存缓存是不会互相干扰的,也就是相互独立的。

解释完内存缓存概念,来看下ASP.NET Core是如何使用内存缓存服务的

  1. ASP.NET Core MVC 项目,框架会自动注入内存缓存服务
  2. ASP.NET Core Web API 等没有自动注入内存缓存服务的项目,需要在Program.cs文件中的builder.Build之前添加builder.Services.AddMemoryCache来把内存缓存相关服务注册到依赖注入容器中
  • 内存缓存的使用

使用内存缓存时,主要使用IMemoryCache接口,这个接口的方法如下

方法说明
bool TryGetValue(object key object value)尝试获取缓存键为key的缓存值,用value参数获取缓存值。如果缓存中没有缓存键为key的缓存值,方法返回true,否则返回false
void Remove(object key)删除缓存键为key的缓存内容
TItem Set<TItem>(object key,TItem value)设置缓存键为key的缓存值为value
TItem GetOrCreate<TItem>(object key,Func<ICacheEntry,TItem> factory)尝试获取缓存键为key的缓存值,方法的返回值为获取的缓存值。如果缓存中没有缓存键为key的缓存值,则调用factory指向的回调从数据源获取数据,把获取的数据作为缓存值保存到缓存中,并且把获取的数据作为方法的返回值。
TItem GetOrCreateAsync<TItem>(object key,Func<ICacheEntry,Task<TItem>> factory)异步版本的GetOrCache方法

这里是一运行结果

操作如下

  1. 先在Program.cs中开启内存缓存服务,记得在builder.Build()

    1. builder.Services.AddMemoryCache();
  2. 创建控制器TestController,注入DbConext, IMemoryCache

    1. [Route("api/[controller]/[action]")]
      [ApiController]
      public class TestController : ControllerBase
      {
              private readonly IMemoryCache memoryCahe;
              private readonly ILogger<TestController> logger;
              public TestController(IMemoryCache memoryCahe, ILogger<TestController> logger, IMemoryCacheHelper memoryCacheHelper, IDistributedCache distributedCache)
              {
                  this.memoryCahe = memoryCahe;
                  this.logger = logger;
                  this.memoryCacheHelper = memoryCacheHelper;
                  this.distributedCache = distributedCache;
              }
              [HttpGet]
              public async Task<ActionResult<Book>> GetBookById1(long id)
              {
                  Console.WriteLine($"开始执行GetBookById,id ={id}");
      
                  logger.LogDebug($"开始执行GetBookById,id ={id}");
      
                  // GetOrCreateAsync.二合一:1)从缓存取数据2)从数据源取数据,并返回给调用者及保存到缓存
                  Book? b = await memoryCahe.GetOrCreateAsync("Book" + id, async (e) =>
                  {
                      Console.WriteLine(($"缓存中没有找到,到数据库中查查,id={id}"));
                      logger.LogDebug($"缓存中没有找到,到数据库中查查,id={id}");
                    
                      Book? book = await MyDbContext.GetByIdAsync(id);
                      Console.WriteLine(($"从数据库查询的结果是" + (book == null ? "null" : book)));
                      return book;
                  });
                  Console.WriteLine($"GetOrCreateAsync结果{b}");
                  logger.LogDebug($"GetOrCreateAsync结果{b}");
                  if (b == null)
                  {
                      return NotFound($"找不到id={id}的书");
                  }
                  else
                  {
                      return Ok(b);
                  }
      
              }
      }
      

运行结果表明,由于我们第一次访问这个路径,缓存还没有对应的数据,因此会先从数据库中查询出对应的数据,再把数据返回给调用者

再次执行时,缓存中已经有了数据,就不会从数据库中获取数据了

5.过期时间
  • 定义理解

上面的缓存的数据正常情况下是不会过期的,也就是执行了一次数据库查询后,就已将数据存进去了,这种情况有个很大的缺点,当我们更新数据时,缓存中的数据会和数据库中的数据不一致,这种问题需要解决。

我们的解决方案是设置合理的过期时间来及时更新缓存,当过期时间到来后,缓存中数据会自动被清除,下次请求时就会重新从数据库中查询,然后再次存入数据库中,达到更新缓存的效果

过期策略有两种:绝对过期时间,滑动过期时间

绝对过期时间:自设置缓存之后的指定时间后,缓存会被清除

滑动过期时间:自设置缓存之后的指定过期时间后,如果对应的缓存没有被访问,缓存则被清除,而如果在缓存过期时间内,有任何访问缓存时,则缓存的过期时间会自动续期

  • 绝对过期时间的使用
			// GetOrCreateAsync.二合一:1)从缓存取数据2)从数据源取数据,并返回给调用者及保存到缓存
            Book? b = await memoryCahe.GetOrCreateAsync("Book" + id, async (e) =>
            {
                Console.WriteLine(($"缓存中没有找到,到数据库中查查,id={id}"));
                logger.LogDebug($"缓存中没有找到,到数据库中查查,id={id}");
                //绝对过期时间
                e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);//缓存有效期十秒        
                Book? book = await MyDbContext.GetByIdAsync(id);
                Console.WriteLine(($"从数据库查询的结果是"+(book==null?"null":book)));
                return book;
            });

在这里插入图片描述

上面是执行了一次缓存后结果,这是设置了10S的过期时间,在此期间,怎么访问都是缓存

在这里插入图片描述

但是在10S之后
在这里插入图片描述

  • 滑动过期时间的使用
e.SlidingExpiration = TimeSpan.FromSeconds(10);

在这里插入图片描述

我们只要在10S内访问一次,就会续期10S,等过了再次访问后
在这里插入图片描述

综上,设置绝对过期时间的缓存会在指定时间后过期,这样即使发生缓存数据不一致的情况,只要我们设置的绝对过期时间比较短,这种不一致的情况不会持续很长的时间,但是如果缓存数据量非常大的话,这些数据会占用很大的内存

而使用滑动过期时间策略,我们可以保证经常访问的数据长期保存在缓存中,但是如果一个缓存项一直被访问,就会一直续期,当我们更新数据时,就会产生缓存与数据库不一致问题,而因为设置了滑动过期策略,且一直在被访问,缓存会一直得不到更新的

  • 混合使用过期时间策略

针对这些情况,我们可以结合绝对过期时间和滑动过期时间进行使用,比如,设置一个绝对过期时间且比滑动过期时间长,这样缓存会在绝对过期时间内随着访问被滑动续期,但是,过了绝对过期时间,缓存项就会被删除

//滑动过期时间和绝对过期时间混用
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30);
e.SlidingExpiration = TimeSpan.FromSeconds(10);

这里可以自行测试…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栀梦星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值