.Net Core3.0 WebApi 项目框架搭建 八:使用Redis做数据缓存

.Net Core3.0 WebApi 项目框架搭建:目录

 

Redis介绍

简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

为什么要用 redis?/为什么要用缓存?

 

主要从“高性能”和“高并发”这两点来看待这个问题。

 

  高性能:

 

  假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!

 

 

高并发:

  直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。

什么数据需要存Redis

欢迎补充:

1.任何可丢失数据

2.不经常变动的数据

Redis安装配置

安装:www.baidu.com,网上一大堆。这里主要配置一下redis连接字符串,在appsetting.json添加Redis配置。

 

  "AppSettings": {
    //数据库连接字符串
    "ConnectionString": "Server=127.0.0.1;User Id=sa;Password=sa123;Database=CoreDB;",
    "JwtSetting": {
      "Issuer": "jwtIssuer", //颁发者
      "Audience": "jwtAudience", //可以给哪些客户端使用
      "SecretKey": "chuangqianmingyueguang" //加密的Key
    },
    "RedisCaching": {
      "Enabled": true,
      "ConnectionString": "47.97.218.139:6379"
    }

 

自定义序列化帮助类

Common的Helper文件夹中,添加SerializeHelper.cs 对象序列化操作

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接口和实现类

Common类库中,新建Redis文件夹,新建IRedisCacheManager接口和RedisCacheManager类,并引用Nuget包StackExchange.Redis

namespace Blog.Core.Common
{
    /// <summary>
    /// Redis缓存接口
    /// </summary>
    public interface IRedisCacheManager
    {

        //获取 Reids 缓存值
        string GetValue(string key);

        //获取值,并序列化
        TEntity Get<TEntity>(string key);

        //保存
        void Set(string key, object value, TimeSpan cacheTime);

        //判断是否存在
        bool Get(string key);

        //移除某一个缓存值
        void Remove(string key);

        //全部清除
        void Clear();
    }
}
public class RedisCacheManager : IRedisCacheManager
    {
        private readonly string redisConnenctionString;
        public volatile ConnectionMultiplexer redisConnection;
        private readonly object redisConnectionLock = new object();
        public RedisCacheManager()
        {
            string redisConfiguration = Appsettings.app(new string[] { "AppSettings", "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}";
            User user = new User();
            if (_redisCacheManager.Get<object>(key) != null)
            {
                user = _redisCacheManager.Get<User>(key);
            }
            else
            {
                user = await _userRepository.GetById(id);
                _redisCacheManager.Set(key, user, TimeSpan.FromHours(2));//缓存2小时
            }

            return Ok(user);
        }

 

F5运行程序,断点查看,第一次运行,redis没有数据

 再次执行,发现用了redis读取出来的数据。

posted @ 2020-05-19 15:19  HuTiger  阅读(4769)  评论(1编辑  收藏  举报