ASP .NET Core 緩存

緩存可以通過減少生成內容所需的工作,顯著提高應用的性能和可伸縮性。 緩存最適用於不常更改且生成成本很高的數據。 緩存生成的數據副本可以比從源中更快地返回。 應該以從不依賴於緩存數據的方式編寫和測試應用。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();
        //非分佈式
        //services.AddMemoryCache();

Redis

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

            services.AddStackExchangeRedisCache(options =>
            {
                options.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions()
                {
                    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 MicrosoftCache
{
    /// <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="distributedCacheEntryOptions">設置Redis緩存的過期策略</param>
        public void Set(string key, object value, DistributedCacheEntryOptions distributedCacheEntryOptions)
        {
            var stringObject = JsonSerializer.Serialize(value, new JsonSerializerOptions
            {
                ReferenceHandler = ReferenceHandler.IgnoreCycles
            });

            var bytesObject = Encoding.UTF8.GetBytes(stringObject);//將Json字符串通過UTF-8編碼,序列化爲字節數組

            cache.Set(key, bytesObject, distributedCacheEntryOptions);
            Refresh(key);//刷新Redis
        }

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


        /// <summary>
        /// Redis中獲取鍵值
        /// </summary>
        /// <typeparam name="T">緩存的類型</typeparam>
        /// <param name="key">緩存鍵</param>
        /// <param name="isExisted">是否獲取到鍵值,true:獲取到了,false:鍵值不存在</param>
        /// <returns>緩存的對象</returns>
        public T Get<T>(string key, out bool isExisted)
        {
            var bytesObject = cache.Get(key);//從Redis中獲取鍵值key的字節數組,如果沒獲取到,那麼會返回null

            if (bytesObject == null)
            {
                isExisted = false;
                return default(T);
            }

            var stringObject = Encoding.UTF8.GetString(bytesObject);//通過UTF-8編碼,將字節數組反序列化爲Json字符串

            isExisted = true;
            return JsonSerializer.Deserialize<T>(stringObject);
        }

        /// <summary>
        /// Redis中刪除鍵值
        /// </summary>
        /// <param name="key">緩存鍵</param>
        public void Remove(string key)=> cache.Remove(key);
        

        /// <summary>
        /// 從Redis中刷新鍵值
        /// </summary>
        /// <param name="key">緩存鍵</param>
        public void Refresh(string key)=>  cache.Refresh(key);
        
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章