zoukankan      html  css  js  c++  java
  • .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下是没有值的,所以,会走下面的代码,进行缓存。

     得到这样的响应结果。我们再来调试一次,看看。

     这次会从缓存中取值。得到的结果,和上面的结果一样。

  • 相关阅读:
    【MySQL疑难杂症】如何将树形结构存储在数据库中(方案二 Path Enumeration)
    【MySQL疑难杂症】如何将树形结构存储在数据库中(方案一 Adjacency List)
    【Java疑难杂症】利用Java核心库实现简单的AOP
    【Java入门提高篇】Day5 Java中的回调(二)
    【Java入门提高篇】Day4 Java中的回调
    【SpringMVC】使用Myeclipse创建SpringMVC项目【超详细教程】
    使用GDAL/OGR读写矢量文件
    WebGL简易教程(四):颜色
    WebGL简易教程(三):绘制一个三角形(缓冲区对象)
    OSG与Shader的结合使用
  • 原文地址:https://www.cnblogs.com/taotaozhuanyong/p/13794499.html
Copyright © 2011-2022 走看看