zoukankan      html  css  js  c++  java
  • Redis学习系列六ZSet(有序列表)及Redis数据结构的过期

     一、简介

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

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

    二、ZSet(有序列表)实战

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

    C#控制台:

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

      /// <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代码如下:

        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扩展如下方法:

            /// <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代码如下:

        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结构对象消失了.其余数据结构自行测试.最好在设置前判断对应的对象存不存在,虽然我试过了,消失了还可以继续设置

  • 相关阅读:
    (转贴)Visual Studio2005 + Visual SourceSafe 2005 实现团队开发、源代码管理、版本控制
    vss2003的资料说明,转贴自MSDN
    非常经典的网络蜘蛛示例,我是转载在这里的
    Vsi的路径所在
    (转)三种模拟自动登录和提交POST信息的实现方法
    (转)关于网络蜘蛛的知识
    (转)thin的制作DataGrid的HTC,转来自己用做开发
    转帖:麻雀虽小,五脏俱全-C# 创建windows服务、socket通讯实例
    Google Maps API编程资源大全
    C#实现的根据年月日计算星期几的函数(转)
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/10182723.html
Copyright © 2011-2022 走看看