.Net Core3.0 WebApi 八:使用Redis做数据缓存
.Net Core3.0 WebApi 目录
Redis介绍
之前的随笔中,也有关于Redis的介绍。这里就简单介绍一下。
简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
为什么要用 redis?/为什么要用缓存?
主要从“高性能”和“高并发”这两点来看待这个问题。
高性能:
假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发:
直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。
什么数据需要存Redis
欢迎补充:
1.任何可丢失数据
2.不经常变动的数据
Redis安装配置
安装:www.baidu.com,网上一大堆。这里主要配置一下redis连接字符串,在appsetting.json添加Redis配置。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ConnectionString": "Data Source=127.0.0.1;Initial Catalog=db;User ID=uid;Password=123456;Pooling=True;Max Pool Size=512;Connect Timeout=500;",
"JwtSetting": {
"Issuer": "jwtIssuer", //颁发者
"Audience": "jwtAudience", //可以给哪些客户端使用
"SecretKey": "chuangqianmingyueguang" //加密的Key
},
"RedisCaching": {
"Enabled": true,
"ConnectionString": "127.0.0.1:6379"
}
}
}
自定义序列化帮助类
Infrastructure的Helpers文件夹中,添加SerializeHelper.cs 对象序列化操作
namespace WebApi.Core.Infrastructure.Helpers { public class SerializeHelper { /// <summary> /// 序列化 /// </summary> /// <param name="item"></param> /// <returns></returns> public static byte[] Serialize(object item) { var jsonString = JsonConvert.SerializeObject(item); return Encoding.UTF8.GetBytes(jsonString); } /// <summary> /// 反序列化 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="value"></param> /// <returns></returns> public static TEntity Deserialize<TEntity>(byte[] value) { if (value == null) { return default(TEntity); } var jsonString = Encoding.UTF8.GetString(value); return JsonConvert.DeserializeObject<TEntity>(jsonString); } } }
定义Redis接口和实现类
Infrastructure类库中,新建Redis文件夹,新建IRedisCacheManager接口和RedisCacheManager类,并引用Nuget包StackExchange.Redis
namespace WebApi.Core.Infrastructure.Redis { public class RedisCacheManager : IRedisCacheManager { private readonly string redisConnenctionString; public volatile ConnectionMultiplexer redisConnection; private readonly object redisConnectionLock = new object(); public RedisCacheManager() { string redisConfiguration = ConfigHelper.GetSectionValue("ConnectionStrings:RedisCaching:ConnectionString");//获取连接字符串 if (string.IsNullOrWhiteSpace(redisConfiguration)) { throw new ArgumentException("redis config is empty", nameof(redisConfiguration)); } this.redisConnenctionString = redisConfiguration; this.redisConnection = GetRedisConnection(); } /// <summary> /// 核心代码,获取连接实例 /// 通过双if 夹lock的方式,实现单例模式 /// </summary> /// <returns></returns> private ConnectionMultiplexer GetRedisConnection() { //如果已经连接实例,直接返回 if (this.redisConnection != null && this.redisConnection.IsConnected) { return this.redisConnection; } //加锁,防止异步编程中,出现单例无效的问题 lock (redisConnectionLock) { if (this.redisConnection != null) { //释放redis连接 this.redisConnection.Dispose(); } try { this.redisConnection = ConnectionMultiplexer.Connect(redisConnenctionString); } catch (Exception) { throw new Exception("Redis服务未启用,请开启该服务"); } } return this.redisConnection; } public void Clear() { foreach (var endPoint in this.GetRedisConnection().GetEndPoints()) { var server = this.GetRedisConnection().GetServer(endPoint); foreach (var key in server.Keys()) { redisConnection.GetDatabase().KeyDelete(key); } } } public bool Get(string key) { return redisConnection.GetDatabase().KeyExists(key); } public string GetValue(string key) { return redisConnection.GetDatabase().StringGet(key); } public TEntity Get<TEntity>(string key) { var value = redisConnection.GetDatabase().StringGet(key); if (value.HasValue) { //需要用的反序列化,将Redis存储的Byte[],进行反序列化 return SerializeHelper.Deserialize<TEntity>(value); } else { return default(TEntity); } } public void Remove(string key) { redisConnection.GetDatabase().KeyDelete(key); } public void Set(string key, object value, TimeSpan cacheTime) { if (value != null) { //序列化,将object值生成RedisValue redisConnection.GetDatabase().StringSet(key, SerializeHelper.Serialize(value), cacheTime); } } public bool SetValue(string key, byte[] value) { return redisConnection.GetDatabase().StringSet(key, value, TimeSpan.FromSeconds(120)); } } }
将Redis服务注入到容器中
将redis接口和类 在ConfigureServices中 进行注入:
//注册Redis services.AddSingleton<IRedisCacheManager, RedisCacheManager>();
控制器中调用
通过构造函数把IRedisCacheManager和UserRepository注入进去,然后新加一个接口。
/// <summary> /// 测试Redis /// </summary> /// <returns></returns> [HttpGet] public async Task<IActionResult> Redis(int id) { var key = $"Redis{id}"; UserNew user = new UserNew(); if (_redisCacheManager.Get<object>(key) != null) { user = _redisCacheManager.Get<UserNew>(key); } else { user = new UserNew { UserId = id, UserName = "bingle", Age = 18 }; _redisCacheManager.Set(key, user, TimeSpan.FromHours(2));//缓存2小时 } return Ok(user); }
运行项目,测试接口。测试接口之前,需要先把Redis服务器开启。
Redis缓存NoSQL 详细的介绍了Redis,docker下安装Redis 以及docker下安装Redis
第一次执行,这个key下是没有值的,所以,会走下面的代码,进行缓存。
得到这样的响应结果。我们再来调试一次,看看。
这次会从缓存中取值。得到的结果,和上面的结果一样。