缓存学习总结3(服务器内存缓存)推荐使用

内存缓存就是一种把缓存数据放到应用程序内存中的机制,内存缓存中保存的是一系列的键值对,就像Dictionary类型一样,每个不同的缓存内容有不同的“缓存键”,每个缓存键对应一个“缓存值”。

我们可以设置缓存的键值对,也可以根据缓存键取出缓存中保存的缓存值。

内存缓存的数据保存在当前运行网站程序的内存中,是和进程相关的。

对于ASP.NET Core MVC项目,框架会自动地注入内存缓存服务,而对于ASP.NET Core WebApi等没有自动注入内存缓存服务的项目,我们需要手动将内存缓存相关服务注册到依赖注入容器中。

下面以ASP.NET Core WebApi项目为例,演示内存缓存的使用方法。

内存缓存的使用

1.创建ASP.NET Core WebApi项目

2.项目添加nuget包的引用

Microsoft.Extensions.Caching.Memory

3.在Startup.cs中对MemoryCache服务注册到依赖注入容器中

4. 创建控制器CacheTestController

在构造方法中,对MemoryCache服务进行注入

控制器中新建两个action:

一个是常规的没有缓存功能,直接获取数据并返回的方法(Test);

另一个是有缓存功能的方法(CacheTest),如果要查询的数据在缓存中存在,则直接返回,如果不存在则将数据查询后存入缓存并返回;

控制器完成代码:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using System;

namespace NetCoreWebApi.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class CacheTestController : ControllerBase
    {
        private readonly IMemoryCache _memoryCache;
        public CacheTestController(IMemoryCache memoryCache)
        {
            _memoryCache = memoryCache;
        }



        /// <summary>
        /// 没有缓存功能的获取数据方法
        /// </summary>
        /// <param name="bookId"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult Test(int bookId)
        {
            Console.WriteLine();
            Console.WriteLine($"开始执行Test方法,bookId={bookId}");
            return DataClass.GetData(bookId);
        }


        /// <summary>
        /// 有缓存功能的获取数据方法
        /// </summary>
        /// <param name="bookId"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult CacheTest(int bookId)
        {
            Console.WriteLine();
            Console.WriteLine($"开始执行CacheTest方法,bookId={bookId}");
            var items = _memoryCache.GetOrCreate("Book" + bookId, (e) =>
              {
                  return DataClass.GetData(bookId);
              });

            Console.WriteLine("把数据返回");
            return items;
        }


    }
}

DataClass类,模拟从数据库查询数据的操作:

using Microsoft.AspNetCore.Mvc;
using System;

namespace NetCoreWebApi
{
    public class DataClass
    {

        public static JsonResult GetData(int bookId)
        {
            Console.WriteLine("数据库被访问");

            //模拟从数据库查询数据
            return new JsonResult(new
            {
                bookId = bookId,
                bookName = BookName(bookId)
            });
        }

        public static string BookName(int bookId)
        {
            switch (bookId)
            {
                case 1:
                    return "书籍1";
                case 2:
                    return "书籍2";
                case 3:
                    return "书籍3";
                default:
                    return "没有查询到书籍名称";
            }
        }
    }
}

5.在页面对webapi接口进行调用

调用没有缓存的方法,入参为1,调用两次,两次都查询了数据库。

调用带有缓存的方法,入参为1,调用两次,只有第一次查询数据库,后面再调用就不会查询数据库,因为缓存中有值,直接从缓存把数据返回。

这时候如果把入参改为2,又会去数据库中查询,因为缓存中只有1的记录,没有2的记录。 

根据上面的方式,设置了缓存后,数据是不会自动过期的,除非重启服务器。

但是在实际的应用中,数据是可能会被改变的。那么就有两种解决方法:

1.在数据改变时,调用Remove或者Set来删除或者修改缓存(优点:及时)。

2.设置过期时间,数据在一段时间内是被缓存的,到期时数据会失效,再次访问,数据又会被缓存起来,也可以保证数据的时效性。

下面介绍方法2,设置数据的缓存过期时间。

缓存过期时间策略

1.绝对过期时间

ICacheEntry的AbsoluteExpirationRelativeToNow属性,用来设置缓存项的绝对过期时间。

 调用结果:

 绝对过期就是在一段时间内缓存数据一直有效,过来这个时间段,缓存就失效。

2.滑动过期时间

只要在缓存没过期的时候被访问,缓存有效期自动更新为设置的时间长度。

例如,缓存的滑动过期时间为10秒钟,在第9秒时被访问,那么缓存的有效期又更新为10秒,只要缓存一直被访问,那就永不过期;超过10秒仍未被访问,那么缓存就失效了。

ICacheEntry的SlidingExpiration属性,用来设置缓存的滑动过期时间。

  调用结果:

 

缓存穿透问题

缓存穿透问题指的是访问的资源不存在,数据为null,导致所有访问都会去查询数据库,从而增加数据库压力的问题。

下面这种写法会引起缓存穿透:

 因为当数据库中不存在查询的数据时,变量b为null,再次访问,又会去访问数据库 。

使用GetOrCreate的写法对数据进行缓存,不会导致缓存穿透,因为查询结果虽然为null,但也会被放入缓存中。

 

缓存雪崩问题

缓存项集中过期,引起请求在一段时间内同时访问数据库,导致数据库压力增大,这样的现象称为缓存雪崩。

解决缓存雪崩问题,可以在缓存的过期时间之上,增加一个随机的过期时间,避免在同一时间内大量缓存项同时失效。

 


版权声明:本文为liangmengbk原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。