前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis学习系列六ZSet(有序列表)及Redis数据结构的过期

Redis学习系列六ZSet(有序列表)及Redis数据结构的过期

作者头像
郑小超.
发布2018-12-28 15:50:27
1.8K0
发布2018-12-28 15:50:27
举报
文章被收录于专栏:GreenLeaves

一、简介

ZSet可以说是Redis中最有趣的数据结构了,因为他兼具了Hash集合和Set的双重特性,也是用的最多的,保证了value值的唯一性的同时,,同时又保证了高性能,最主要的是还可以给每个Value设置Source(权重),那么我们就可以通过权重进行排序,这在业务上是非常常见的,比如很多地方需要,比如我们需要对所有用户的数学成绩进行排序.对英语等等地例子比比皆是,那么通过ZSet,你将会得到一个响应速度非常快的过程.下面会介绍.

ZSet的内部原理是通过跳跃列表来实现的,这里还是不想说太多关于算法的东西.

二、ZSet(有序列表)实战

下面就通过一个列子来讲解,主要是给所有用户的数学成绩进行排序的例子.代码开始在前面的随笔上进行扩展.

C#控制台:

给RedisClient.cs扩展如下几个方法:

代码语言:javascript
复制
  /// <summary> 
        /// 异步不带权重的向有序列表批量插入数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static async Task<long> SortedSetAddAsync(RedisKey key, SortedSetEntry[] entries)
        {
            var db = GetDatabase();
            return await db.SortedSetAddAsync(key, entries);
        }

        /// <summary> 
        /// 异步带权重的向有序列表插入单个元素,不管是否存在已有元素,都执行插入操作
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static async Task<RedisValue> SortedSetAddAsync(RedisKey key, RedisValue value,double source)
        {
            var db = GetDatabase();
            return await db.SortedSetAddAsync(key, value, source);
        }

        /// <summary>
        /// 异步按权重(范围为负无穷大到正无穷大排序)得到所有的元素,返回的元素(不包含权重)集合默认的排序时按权重从低到高,可指定权重
        /// </summary>
        /// <param name="key"></param>
        /// <param name="start">权重下限</param>
        /// <param name="stop">权重上限</param>
        /// <returns></returns>
        public static async Task<RedisValue[]> SortedSetRangeByScoreAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
        {
            var db = GetDatabase();
            return await db.SortedSetRangeByScoreAsync(key, start, stop);
        }

        /// <summary>
        /// 异步按权重(范围为负无穷大到正无穷大排序)得到所有的元素,返回的元素(包含权重)集合默认的排序时按权重从低到高,可指定权重
        /// </summary>
        /// <param name="key"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public static async Task<SortedSetEntry[]> SortedSetRangeByScoreWithScoresAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
        {
            var db = GetDatabase();
            return await db.SortedSetRangeByScoreWithScoresAsync(key, start,stop);
        }

        /// <summary>
        /// 异步按权重(范围为负无穷大到正无穷大排序)得到所有的元素,返回的元素(包含权重)集合默认的排序时按权重从高到低,可指定权重
        /// </summary>
        /// <param name="key"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public static async Task<SortedSetEntry[]> SortedSetRangeByScoreWithScoresDescendingAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
        {
            var db = GetDatabase();
            return await db.SortedSetRangeByScoreWithScoresAsync(key, start, stop,Exclude.None, Order.Descending);
        }

        /// <summary>
        /// 异步按权重范围,删除对应键下的所有元素
        /// </summary>
        /// <param name="key"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public static async Task<long> SortedSetRemoveRangeByScoreAsync(RedisKey key, double start = double.NegativeInfinity, double stop = double.PositiveInfinity)
        {
            var db = GetDatabase();
            return await db.SortedSetRemoveRangeByScoreAsync(key, start, stop);
        }

        /// <summary>
        /// 异步删除指定键下的指定值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static async Task<bool> SortedSetRemoveAsync(RedisKey key, RedisValue value)
        {
            var db = GetDatabase();
            return await db.SortedSetRemoveAsync(key, value);
        }

还可以继续扩展,个人觉得其它方法没什么用,就没有继续扩展了.

Program.cs代码如下:

代码语言:javascript
复制
    class Program
    {
        static Program()
        {
            //链式配置Redis
            AppConfiguration.Current.ConfigureRedis<RedisConfig>();
        }

        static void Main(string[] args)
        {
            StringSetGetAsync();
            Console.ReadKey();
        }

        static async void StringSetGetAsync()
        {
            var key = "math";
            var computer = new KeyValuePair<RedisValue, double>("小超的用户Id", 9.0);
            var english = new KeyValuePair<RedisValue, double>("大超的用户Id", 8.0);
            var math = new KeyValuePair<RedisValue, double>("中超的用户Id", 7.0);
            var chinese = new KeyValuePair<RedisValue, double>("大大超的用户Id", 10.0);
            try
            {
                await RedisClient.SortedSetAddAsync(key, new SortedSetEntry[] { computer, math, english, chinese });

                //模拟重复插入,不会发现插入没有效果,因为Zset自带去重功能是Set和Hash的组合体
                await RedisClient.SortedSetAddAsync(key, new SortedSetEntry[] { computer, math, english });

                Console.WriteLine("输出指定键的所有元素(不包含权重),默认按权重从小到大排序");
                //输出指定键的所有元素(不包含权重),默认按权重从小到大排序
                var values =await RedisClient.SortedSetRangeByScoreAsync(key);
                foreach (var val in values)
                {
                    Console.WriteLine("值为:{0}",val);
                }
                Console.WriteLine("输出指定键的所有元素(包含权重),默认按权重从小到大排序");
                //输出指定键的所有元素(包含权重),默认按权重从小到大排序
                var oValues= await RedisClient.SortedSetRangeByScoreWithScoresAsync(key);
                foreach (var oVal in oValues)
                {
                    Console.WriteLine("值为:{0},权重为:{1}",oVal.Element,oVal.Score);
                }

                Console.WriteLine("输出指定键的所有元素(包含权重),按权重从大到小排序");
                //输出指定键的所有元素(包含权重),按权重从大到小排序,权重范围为7~8
                var lValues = await RedisClient.SortedSetRangeByScoreWithScoresDescendingAsync(key,7,8);
                foreach (var lVal in lValues)
                {
                    Console.WriteLine("值为:{0},权重为:{1}", lVal.Element, lVal.Score);
                }
                try
                {
                    await RedisClient.SortedSetRemoveRangeByScoreAsync(key, 7, 8);
                    Console.WriteLine("删除key为:{0}下权重为7~8之间的所有元素成功!", key);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("删除元素发生了异常,信息为{0}", ex.Message);
                }
                var extraValues = await RedisClient.SortedSetRangeByScoreWithScoresAsync(key);
                foreach (var eVal in extraValues)
                {
                    Console.WriteLine("值为:{0},权重为:{1}", eVal.Element, eVal.Score);
                }

                //输出一个指定键下的指定值
                try
                {
                    var value = "大大超的用户Id";
                    await RedisClient.SortedSetRemoveAsync(key, value);
                    Console.WriteLine("删除key为:{0}下值为:{1}的元素成功!", key, value);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("删除元素发生了异常,信息为{0}", ex.Message);
                }

                var exValues = await RedisClient.SortedSetRangeByScoreWithScoresAsync(key);
                foreach (var exVal in exValues)
                {
                    Console.WriteLine("值为:{0},权重为:{1}", exVal.Element, exVal.Score);
                }

            }
            catch (Exception ex)
            {
                //记录日志
                Console.WriteLine(ex.Message);
            }
        }
    }

上面的权重就是实际的分数,ok,是不是很强大!

三、给Redis数据结构设置过期时间

到这里Redis的5大基本数据结构算介绍完了,该讲讲过期的知识,Redis的所有数据结构都可以设置过期时间,时间一到,Redis会自动删除相应的对象,注意:Redis的5大基本数据结构基本都是键值对的关系,最外部有个键来指定整个对象,所以Redis的删除是争对该键对应的对象的.但是Hash结构中,除了指定外部的键还可以指定内部的键.向下面这样:

但是Redis的过期是争对最外部的键的.就是整个数据结构.

注:关于String结构也有点特殊,因为它本身也可以设置过期时间,如果你已经给一个字符串设置了过期时间,然后调用了过期Api修改它,它原先的过期时间会消失.

给RedisClient.cs扩展如下方法:

代码语言:javascript
复制
        /// <summary>
        /// 异步给指定的键的对象设置过期时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timeSpan"></param>
        /// <returns></returns>
        public static async Task<bool> KeyExpireAsync(RedisKey key,TimeSpan timeSpan)
        {
            var db = GetDatabase();
            return await db.KeyExpireAsync(key, timeSpan);
        }

Program.cs代码如下:

代码语言:javascript
复制
    class Program
    {
        static Program()
        {
            //链式配置Redis
            AppConfiguration.Current.ConfigureRedis<RedisConfig>();
        }

        static void Main(string[] args)
        {
            StringSetGetAsync();
            Console.ReadKey();
        }

        static async void StringSetGetAsync()
        {
            var key = "math";
            try
            {
                await RedisClient.KeyExpireAsync(key, TimeSpan.FromMilliseconds(1000));
                Console.WriteLine("给指定的键设置过期时间异常成功.");
            }
            catch (Exception ex)
            {
                Console.WriteLine("给指定的键设置过期时间异常,信息为:{0}.", ex.Message);
            }
            
        }
    }

对应键为math的ZSet结构对象消失了.其余数据结构自行测试.最好在设置前判断对应的对象存不存在,虽然我试过了,消失了还可以继续设置

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis®
腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档