ASP .NET Core DistributedCache缓存

缓存可以通过减少生成内容所需的工作,显著提高应用的性能和可伸缩性。 缓存最适用于不常更改且生成成本很高的数据。 缓存生成的数据副本可以比从源中更快地返回。 应该以从不依赖于缓存数据的方式编写和测试应用。ASP.NET Core 支持多个不同的缓存。

本文主要介绍五种缓存方式

缓存类别 Nuget
Memory内存 Microsoft.Extensions.Caching.Memory
SqlServer Microsoft.Extensions.Caching.SqlServer
Redis Microsoft.Extensions.Caching.StackExchangeRedis
Mysql Pomelo.Extensions.Caching.MySql
PostgreSql Community.Microsoft.Extensions.Caching.PostgreSql

第三方缓存帮助包

添加缓存服务

Memory

services.AddDistributedMemoryCache();

Redis

            services.AddStackExchangeRedisCache(options =>
            {
                options.Configuration = "192.168.1.105:6379,password=1qaz@WSX3edc$RFV,ssl=False,abortConnect=False,defaultDatabase=2";
                options.InstanceName = "App-Instance-Keys";
            });

            services.AddStackExchangeRedisCache(options =>
            {
                options.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions()
                {
                    DefaultDatabase=2,
                    Password = "1qaz@WSX3edc$RFV",
                    ConnectTimeout = 5000,//设置建立连接到Redis服务器的超时时间为5000毫秒
                    SyncTimeout = 5000,//设置对Redis服务器进行同步操作的超时时间为5000毫秒
                    ResponseTimeout = 5000,//设置对Redis服务器进行操作的响应超时时间为5000毫秒
                    Ssl = false,//设置启用SSL安全加密传输Redis数据
                    //SslHost=""
                    //SslProtocols = System.Security.Authentication.SslProtocols.Tls//还可以通过SslProtocols属性指定SSL具体用到的是什么协议,不过这个属性不是必须的
                };

                options.ConfigurationOptions.EndPoints.Add("192.168.1.105:6379");
                options.InstanceName = "App-Instance-Keys";
            });

SqlServer

        services.AddDistributedSqlServerCache(options =>
        {
            options.SchemaName = "dbo";
            options.ConnectionString = Configuration["SqlServerConnection"];
            //表名
            options.TableName = "TestCache";
            //默认缓存时间
            options.DefaultSlidingExpiration = TimeSpan.FromMinutes(20);
            //过时自动删除
            options.ExpiredItemsDeletionInterval = TimeSpan.FromMinutes(30);
        });

命令行创建表

#默认安装最新版
dotnet tool install --global dotnet-sql-cache  

#安装指定版本
#dotnet tool install --global dotnet-sql-cache --version 6.0.0

#创建缓存表
dotnet sql-cache create "Data Source=127.0.0.1;Database=Test;Uid=sa;Pwd=123456;"  dbo  TestCache

出现Table and index were created successfully.代表创建成功

Sql脚本创建表

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TestCache](
	[Id] [nvarchar](449) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
	[Value] [varbinary](max) NOT NULL,
	[ExpiresAtTime] [datetimeoffset](7) NOT NULL,
	[SlidingExpirationInSeconds] [bigint] NULL,
	[AbsoluteExpiration] [datetimeoffset](7) NULL,
PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

CREATE NONCLUSTERED INDEX [Index_ExpiresAtTime] ON [dbo].[TestCache]
(
	[ExpiresAtTime] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

查看缓存表数据SELECT * FROM TestCache

Mysql

services.AddDistributedMySqlCache(options => {
    //数据库名称
    options.SchemaName = "dbName";

    //AllowUserVariables必须加不然会报错
    options.ConnectionString = "server=127.0.0.1;uid=root;pwd=123456;database=mysql;port=3306;pooling=false;SslMode=None;old Guids=true;Charset=utf8;AllowUserVariables=true;";
    //表名
    options.TableName = "testcache";
    //默认缓存时间
    options.DefaultSlidingExpiration = TimeSpan.FromMinutes(20);
    //过时自动删除
    options.ExpiredItemsDeletionInterval = TimeSpan.FromMinutes(30);
});

命令行创建表

#默认安装最新版
dotnet tool install --global Pomelo.Extensions.Caching.MySqlConfig.Tools  

#创建缓存表(mysql是指数据库名称)
dotnet-mysql-cache create "server=127.0.0.1;uid=root;pwd=123456;database=mysql;port=3306;pooling=false;SslMode=None;old Guids=true;Charset=utf8;" mysql TestCache

出现Table and index were created successfully.代表创建成功

Sql脚本创建表

# DROP TABLE IF EXISTS `testcache`;
CREATE TABLE `testcache` (
  `Id` varchar(449) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
  `AbsoluteExpiration` datetime(6) DEFAULT NULL,
  `ExpiresAtTime` datetime(6) NOT NULL,
  `SlidingExpirationInSeconds` bigint DEFAULT NULL,
  `Value` longblob NOT NULL,
  PRIMARY KEY (`Id`),
  KEY `Index_ExpiresAtTime` (`ExpiresAtTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

PostgreSql

--using Community.Microsoft.Extensions.Caching.PostgreSql;

services.AddDistributedPostgreSqlCache(options =>
{
    options.ConnectionString = "host=127.0.0.1;Port=5432;database=postgres;username=postgres;password=123456;";
    //模式
    options.SchemaName = "public";
    //表名
    options.TableName = "tbl_cache";
    //默认过期时间
    options.DefaultSlidingExpiration = TimeSpan.FromMinutes(20);
    //过时自动删除
    options.ExpiredItemsDeletionInterval = TimeSpan.FromMinutes(5);
});

程序运行后会自动创建模式和表。或者使用Sql脚本手动创建。

使用缓存

DistributedCacheEntryOptions是设置缓存时间的配置类

        //设置十分钟后过期
        new DistributedCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(10));

        //设置以当前时间为例,十分钟后过期
        new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTimeOffset.Now.AddMinutes(10));

        new DistributedCacheEntryOptions {
            //设置未来某一个时间过期
            AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(10),
            //设置以当前时间为例,过过长时间过期,案例为10分钟
            //AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
        };

设置缓存

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Threading.Tasks;

namespace MicrosoftCache.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class RedisController : ControllerBase
    {
        private readonly IDistributedCache _distributedCache;

        public RedisController(IDistributedCache distributedCache)
        {
            _distributedCache = distributedCache;
        }

        [HttpGet]
        public async Task Get()
        {
            //设置十分钟后过期
           var dco=  new DistributedCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(10));

            string key = "demokey";

            //添加/修改缓存时间
            _distributedCache.SetString(key, "123456", dco);

            //异步缓存
            await _distributedCache.SetStringAsync("demokeyAsync", "123456", dco);

            //获取缓存数据
            var getvlaue = _distributedCache.GetString(key);


            //刷新
            _distributedCache.Refresh(key);

            //删除
            _distributedCache.Remove(key);


            object value = new { id=1,user = "zs" };

            var stringObject = System.Text.Json.JsonSerializer.Serialize(value, new System.Text.Json.JsonSerializerOptions
            {
                //.Net6+
                ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles
            });

            var bytesObject = System.Text.Encoding.UTF8.GetBytes(stringObject);//将Json字符串通过UTF-8编码,序列化为字节数组

            //设置byte 缓存
            _distributedCache.Set(key, bytesObject, dco);
            //刷新Redis
            _distributedCache.Refresh(key);



            //获取byte 缓存数据
            var bytesGetObject = _distributedCache.Get(key);
            var stringGetObject = System.Text.Encoding.UTF8.GetString(bytesGetObject);//通过UTF-8编码,将字节数组反序列化为Json字符串
            var bytevlaue = System.Text.Json.JsonSerializer.Deserialize<object>(stringGetObject);
        }
    }
}

缓存帮助类

using Microsoft.Extensions.Caching.Distributed;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace WebApplication1
{
    /// <summary>
    /// Cache缓存操作类
    /// </summary>
    public class CacheHelper
    {
        protected IDistributedCache cache;

        /// <summary>
        /// 通过IDistributedCache来构造RedisCache缓存操作类
        /// </summary>
        /// <param name="cache">IDistributedCache对象</param>
        public CacheHelper(IDistributedCache cache)
        {
            this.cache = cache;
        }

        /// <summary>
        /// 添加或更改Redis的键值,并设置缓存的过期策略
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存对象</param>
        /// <param name="timeSpan">设置Redis缓存的过期策略</param>
        public void Set(string key, object value, TimeSpan timeSpan)
        {
            string stringObject = JsonSerializer.Serialize(value,
                new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.IgnoreCycles });

            Set(key, stringObject, timeSpan);
        }

        /// <summary>
        /// 添加或更改Redis的键值,并设置缓存的过期策略
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存string</param>
        /// <param name="timeSpan">设置Redis缓存的过期策略</param>
        public void SetString(string key, string value, TimeSpan timeSpan) => Set(key, value, timeSpan);


        /// <summary>
        /// 查询键值是否在Redis中存在
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>true:存在,false:不存在</returns>
        public bool Exist(string key) => cache.Get(key) != null;

        /// <summary>
        /// Redis中删除键值
        /// </summary>
        /// <param name="key">缓存键</param>
        public void Remove(string key) => cache.Remove(key);

        /// <summary>
        /// Redis中获取键值
        /// </summary>
        /// <typeparam name="T">缓存的类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <returns>缓存对象</returns>
        public T? Get<T>(string key)
        {
            var bytesObject = cache.Get(key);
            return bytesObject == null ? default(T) : JsonSerializer.Deserialize<T>(Encoding.UTF8.GetString(bytesObject));
        }

        /// <summary>
        /// Redis中获取键值
        /// </summary>
        /// <typeparam name="T">缓存的类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <returns>缓存String</returns>
        public string? GetString(string key)
        {
            var bytesObject = cache.Get(key);
            return bytesObject == null ? null : Encoding.UTF8.GetString(bytesObject);
        }

        /// <summary>
        /// 添加或更改Redis的键值,并设置缓存的过期策略
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存值一般是对象</param>
        /// <param name="timeSpan">设置Redis缓存的过期策略</param>
        private void Set(string key, string value, TimeSpan timeSpan)
        {
            var distributedCacheEntryOptions = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = timeSpan };
            cache.Set(key, Encoding.UTF8.GetBytes(value), distributedCacheEntryOptions);
            cache.Refresh(key);//刷新Redis
        }
    }
}
posted @ 2022-11-24 00:02  雨水的命运  阅读(655)  评论(0编辑  收藏  举报