• StackExchange.Redis 之 List队列 类型示例


                //从第1个开始,依次向左插入值。如果键不存在,先创建再插入值  队列形式 先进后出,后进先出
    //插入后形式  <-- 10,9,8,7,6,5,4,3,2,1 <-- 方向向左依次进行
    stopwatch.Start(); for (int i = 0; i < 10; i++) { var getobjlist = RedisCacheHelper.Instance.ListLeftPush("leftlistkey", (i + 1).ToString()); } stopwatch.Stop(); Console.WriteLine("在列表头部插入值消耗时间:" + stopwatch.ElapsedMilliseconds.ToString()); //从第1个开始,依次向右插入值。如果键不存在,先创建再插入值 先进先出,后进后出
    //插入后形式  1,2,3,4,5,6,7,8,9,10 --> 方向向右依次进行
    stopwatch.Start(); for (int i = 0; i < 10; i++) { var getobjlist = RedisCacheHelper.Instance.ListRightPush("rightlistkey", (i + 1).ToString()); } stopwatch.Stop(); Console.WriteLine("在列表尾部插入值消耗时间:" + stopwatch.ElapsedMilliseconds.ToString());

     

     

                //获取Left列表中的队列元素  从列表头部开始读取
                var getleftvalue = RedisCacheHelper.Instance.ListRange("leftlistkey");
                Console.WriteLine(string.Join(",", getleftvalue));
    
    
                //获取Right列表中的队列元素   从列表头部开始读取
                var getrightvalue = RedisCacheHelper.Instance.ListRange("rightlistkey");
                Console.WriteLine(string.Join(",", getrightvalue));

                //从左边第一个元素开始  循环移除并返回该移除的值
                Console.WriteLine("从左边开始");
                while (true)
                {
                    var getleftvalue = RedisCacheHelper.Instance.ListLeftPop("leftlistkey");
                    if (!string.IsNullOrEmpty(getleftvalue))
                    {
                        Console.WriteLine("移除:" + getleftvalue);
                    }
                    else
                    {
                        break;
                    }
                }
    
                //从右边第一个元素开始  循环移除并返回该移除的值  
                Console.WriteLine("从右边开始");
                while (true)
                {
                    var getrightvalue = RedisCacheHelper.Instance.ListRightPop("rightlistkey");
                    if (!string.IsNullOrEmpty(getrightvalue))
                    {
                        Console.WriteLine("移除:" + getrightvalue);
                    }
                    else
                    {
                        break;
                    }
                }

                //从左边第一个元素开始  循环移除并返回该移除的值  替换一下Key后
                Console.WriteLine("从左边开始");
                while (true)
                {
                    var getleftvalue = RedisCacheHelper.Instance.ListLeftPop("rightlistkey");
                    if (!string.IsNullOrEmpty(getleftvalue))
                    {
                        Console.WriteLine("移除:" + getleftvalue);
                    }
                    else
                    {
                        break;
                    }
                }
    
    
                //从右边第一个元素开始  循环移除并返回该移除的值  替换一下Key后
                Console.WriteLine("从右边开始");
                while (true)
                {
                    var getrightvalue = RedisCacheHelper.Instance.ListRightPop("leftlistkey");
                    if (!string.IsNullOrEmpty(getrightvalue))
                    {
                        Console.WriteLine("移除:" + getrightvalue);
                    }
                    else
                    {
                        break;
                    }
                }

                //列表长度  不存在则返回0
                var getlength = RedisCacheHelper.Instance.ListLength("leftlistkey");
                Console.WriteLine("列表长度:" + getlength);
    
                //删除List中的元素 并返回删除的个数    不存在则返回0
                var getlong = RedisCacheHelper.Instance.ListDelRange("leftlistkey", "6");
                Console.WriteLine("删除List中的元素,并返回删除的个数:" + getlong);
    
                //清空列表
                RedisCacheHelper.Instance.ListClear("leftlistkey");

    使用List类型 模拟用户并发抢购商品

    //模拟数据  想List类型表中加入一定数量的库存   50个商品
                for (int i = 1; i <= 50; i++)
                {
                    var getvalue = RedisCacheHelper.Instance.ListRightPush("orderlist", i.ToString());
                    //Console.WriteLine("返回结果:" + getvalue);
                }
    
                //模拟创建多个用户  100个用户
                List<TestRedis> testlist = new List<TestRedis>();
                for (int i = 0; i < 100; i++)
                {
                    testlist.Add(new TestRedis() { Uid = (i + 1) });
                }
    
                //先清空
                RedisCacheHelper.Instance.ListClear("orderSuccessList");
    
                //使用List类型模拟并发情况  不用担心库存为负的情况
                //模拟多个用户抢购限时商品   100个用户抢50个商品
                stopwatch.Start();
                List<Task> taskList = new List<Task>();
                foreach (var item in testlist)
                {
                    var task = Task.Run(() =>
                    {
                        try
                        {
                            //先自减,获取自减后的值
                            long order_Num = -1;
                            long.TryParse(RedisCacheHelper.Instance.ListRightPop("orderlist"), out order_Num);
                            if (order_Num > 0)
                            {
                                //下面执行订单逻辑(这里不考虑业务出错的情况)
    
                                RedisCacheHelper.Instance.ListLeftPush("orderSuccessList", item.Uid.ToString());  //记录下单成功的用户
    
                                //操作数据库相关逻辑 可以使用“消息队列”或“服务”进行数据库同步操作
    
                                Console.WriteLine("用户:" + item.Uid + ",抢到了商品:" + order_Num);
                            }
                            else
                            {
                                Console.WriteLine("商品已经被抢光了,用户" + item.Uid + "未抢到");
                            }
    
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                            throw;
                        }
                    });
                    taskList.Add(task);
                }
                Task.WaitAll(taskList.ToArray());
                stopwatch.Stop();
                Console.WriteLine("模拟并发场景消耗时间:" + stopwatch.ElapsedMilliseconds.ToString());

     

    应用场景:

    Redis list 的应用场景非常多,也是 Redis 最重要的数据结构之一,比如 twitter 的关注列表,粉丝列表等都可以用 Redis 的 list 结构来实现,比较好理解,这里不再重复。

    实现方式:

    Redis list 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis 内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

    最后附上Helper

            /// <summary>
            /// 在列表头部插入值。如果键不存在,先创建再插入值
            /// </summary>
            /// <param name="redisKey"></param>
            /// <param name="redisValue"></param>
            /// <returns></returns>
            public long ListLeftPush(string redisKey, string redisValue, int db = -1)
            {
                var _db = GetDatabase(db);
                return _db.ListLeftPush(redisKey, redisValue);
            }
            /// <summary>
            /// 在列表尾部插入值。如果键不存在,先创建再插入值
            /// </summary>
            /// <param name="redisKey"></param>
            /// <param name="redisValue"></param>
            /// <returns></returns>
            public long ListRightPush(string redisKey, string redisValue, int db = -1)
            {
                var _db = GetDatabase(db);
                return _db.ListRightPush(redisKey, redisValue);
            }
    
            /// <summary>
            /// 在列表尾部插入数组集合。如果键不存在,先创建再插入值
            /// </summary>
            /// <param name="redisKey"></param>
            /// <param name="redisValue"></param>
            /// <returns></returns>
            public long ListRightPush(string redisKey, IEnumerable<string> redisValue, int db = -1)
            {
                var _db = GetDatabase(db);
                var redislist = new List<RedisValue>();
                foreach (var item in redisValue)
                {
                    redislist.Add(item);
                }
                return _db.ListRightPush(redisKey, redislist.ToArray());
            }
    
    
            /// <summary>
            /// 移除并返回存储在该键列表的第一个元素  反序列化
            /// </summary>
            /// <param name="redisKey"></param>
            /// <returns></returns>
            public T ListLeftPop<T>(string redisKey, int db = -1) where T : class
            {
                var _db = GetDatabase(db);
                return JsonConvert.DeserializeObject<T>(_db.ListLeftPop(redisKey));
            }
    
            /// <summary>
            /// 移除并返回存储在该键列表的最后一个元素   反序列化
            /// 只能是对象集合
            /// </summary>
            /// <param name="redisKey"></param>
            /// <returns></returns>
            public T ListRightPop<T>(string redisKey, int db = -1) where T : class
            {
                var _db = GetDatabase(db);
                return JsonConvert.DeserializeObject<T>(_db.ListRightPop(redisKey));
            }
    
            /// <summary>
            /// 移除并返回存储在该键列表的第一个元素   
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="redisKey"></param>
            /// <param name="db"></param>
            /// <returns></returns>
            public string ListLeftPop(string redisKey, int db = -1)
            {
                var _db = GetDatabase(db);
                return _db.ListLeftPop(redisKey);
            }
    
            /// <summary>
            /// 移除并返回存储在该键列表的最后一个元素   
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="redisKey"></param>
            /// <param name="db"></param>
            /// <returns></returns>
            public string ListRightPop(string redisKey, int db = -1)
            {
                var _db = GetDatabase(db);
                return _db.ListRightPop(redisKey);
            }
    
            /// <summary>
            /// 列表长度
            /// </summary>
            /// <param name="redisKey"></param>
            /// <param name="db"></param>
            /// <returns></returns>
            public long ListLength(string redisKey, int db = -1)
            {
                var _db = GetDatabase(db);
                return _db.ListLength(redisKey);
            }
    
            /// <summary>
            /// 返回在该列表上键所对应的元素
            /// </summary>
            /// <param name="redisKey"></param>
            /// <returns></returns>
            public IEnumerable<string> ListRange(string redisKey, int db = -1)
            {
                var _db = GetDatabase(db);
                var result = _db.ListRange(redisKey);
                return result.Select(o => o.ToString());
            }
    
            /// <summary>
            /// 根据索引获取指定位置数据
            /// </summary>
            /// <param name="redisKey"></param>
            /// <param name="start"></param>
            /// <param name="stop"></param>
            /// <param name="db"></param>
            /// <returns></returns>
            public IEnumerable<string> ListRange(string redisKey, int start, int stop, int db = -1)
            {
                var _db = GetDatabase(db);
                var result = _db.ListRange(redisKey, start, stop);
                return result.Select(o => o.ToString());
            }
    
            /// <summary>
            /// 删除List中的元素 并返回删除的个数
            /// </summary>
            /// <param name="redisKey">key</param>
            /// <param name="redisValue">元素</param>
            /// <param name="type">大于零 : 从表头开始向表尾搜索,小于零 : 从表尾开始向表头搜索,等于零:移除表中所有与 VALUE 相等的值</param>
            /// <param name="db"></param>
            /// <returns></returns>
            public long ListDelRange(string redisKey, string redisValue, long type = 0, int db = -1)
            {
                var _db = GetDatabase(db);
                return _db.ListRemove(redisKey, redisValue, type);
            }
    
            /// <summary>
            /// 清空List
            /// </summary>
            /// <param name="redisKey"></param>
            /// <param name="db"></param>
            public void ListClear(string redisKey, int db = -1)
            {
                var _db = GetDatabase(db);
                _db.ListTrim(redisKey, 1, 0);
            }
    View Code
  • 相关阅读:
    【Thymeleaf】利用status对象在th:each语法中显示index
    【Oracle】使用Regexp_like 判断varchar2,nvarchar2型字段里中值是否全由数字组成
    [轉]相機光圈
    選購數碼相機
    [轉載]找不到SQL server ODBC驱动程序的安装例程!请重新安装驱动程序
    [轉]解读GIF文件
    [轉]【经典问题】关于JS验证文本框输入只能输入半角,不让输入全角
    WebGenie
    XML和HTML常用转义字符
    PHP招聘启示
  • 原文地址:https://www.cnblogs.com/peterzhang123/p/12322353.html
Copyright © 2020-2023  润新知