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