c# redis系列二

Hash

Hash:key--Dictionary,

1 节约空间(zipmap的紧密摆放的存储模式)

2 更新/访问方便(hashid+key) Hash数据很像关系型数据库的表的一行数据, 但是字段是可以随意定制的,没有严格约束的,非常灵活

如果说我们要存储一个模型,如果还是存储string类型的话就得将其序列化,使用的时候取出来之后还是要再次反序列化,这样太麻烦了。

Hash:类似dictionary,通过索引快速定位到指定元素的,耗时均等,跟string的区别在于不用反序列化,直接修改某个字段;string的话要么是 001:序列化整个实体,要么是 001_name: 001_pwd: 多个key-value,Hash的话,一个hashid-{key:value;key:value;key:value;}可以一次性查找实体,也可以单个,还可以单个修改

如果是存string类型的话,后面做更改的话就需要全部取出来,然后更改,更改完之后再重新存储,这样的话就会存在问题,万一更改过程中出现其他问题,比如多线程之类的导致其他数据出现问题。如果使用hash的话可以直接更改指定元素,不必取出,保证了原子性,性能还高。

模型类:

    public class UserInfo
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Account { get; set; }
        public string Password { get; set; }
        public string Email { get; set; }
        public string Address { get; set; }
        public long QQ { get; set; }
    }

 

string类型示例:

{
                    //service.FlushAll();//删除所有的Redis缓存
                    string key = $"userInfo_{user.Id}";
                    //这是redis内部自动对UserInfo做了序列化
                    service.Set<UserInfo>(key, user);
                    //取出来也是redis内部做的反序列化
                    List<UserInfo> userList = service.Get<UserInfo>(new List<string>() { key });
                    UserInfo updateUser = userList.FirstOrDefault();
                    updateUser.Account = "Admin";
                    service.Set<UserInfo>(key, updateUser);
                }

 

hash:

   using (RedisHashService service = new RedisHashService())
            {
                service.FlushAll();
                service.SetEntryInHash($"UserInfo_{user.Id}", "Name", user.Name);
                service.SetEntryInHash($"UserInfo_{user.Id}", "Account", user.Account);
                //如果在这个hashid中已经存在一个key,再次执行SetEntryInHash方法就会覆盖上一个值,也可以当做修改方法使用
                service.SetEntryInHash($"UserInfo_{user.Id}", "Name", user.Address);
                service.SetEntryInHash($"UserInfo_{user.Id}", "Name", user.Email);
                service.GetValueFromHash($"UserInfo_{user.Id}", "Name");
                //目标是最好是一个Api 去定位到某一个数据,直接在Redis 层面就给改掉!
                //Hash存储是有Api 直接修改某一个;
            }

 hash存储是这种结构:

 

 Set存储

 

 

 

Set存储value值自动去重,使用场景: IP统计去重; 添加好友申请; 投票限制; 点赞;

封装的一些常用的api:

  /// <summary>
    /// Set:用哈希表来保持字符串的唯一性,没有先后顺序,存储一些集合性的数据
    /// 1.共同好友、二度好友
    /// 2.利用唯一性,可以统计访问网站的所有独立 IP
    /// </summary>
    public class RedisSetService : RedisBase
    {
        #region 添加
        /// <summary>
        /// key集合中添加value值
        /// </summary>
        public void Add(string key, string value)
        {
            base.iClient.AddItemToSet(key, value);
        }
        /// <summary>
        /// key集合中添加list集合
        /// </summary>
        public void Add(string key, List<string> list)
        {
            base.iClient.AddRangeToSet(key, list);

        }
        #endregion

        #region 获取
        /// <summary>
        /// 随机获取key集合中的一个值
        /// </summary>
        public string GetRandomItemFromSet(string key)
        {
            return base.iClient.GetRandomItemFromSet(key);
        }
        /// <summary>
        /// 获取key集合值的数量
        /// </summary>
        public long GetCount(string key)
        {
            return base.iClient.GetSetCount(key);
        }
        /// <summary>
        /// 获取所有key集合的值
        /// </summary>
        public HashSet<string> GetAllItemsFromSet(string key)
        {
            return base.iClient.GetAllItemsFromSet(key);
        }
        #endregion

        #region 删除
        /// <summary>
        /// 随机删除key集合中的一个值
        /// </summary>
        public string RandomRemoveItemFromSet(string key)
        {
            return base.iClient.PopItemFromSet(key);
        }
        /// <summary>
        /// 删除key集合中的value
        /// </summary>
        public void RemoveItemFromSet(string key, string value)
        {
            base.iClient.RemoveItemFromSet(key, value);
        }
        #endregion

        #region 其它
        /// <summary>
        /// 从fromkey集合中移除值为value的值,并把value添加到tokey集合中
        /// </summary>
        public void MoveBetweenSets(string fromkey, string tokey, string value)
        {
            base.iClient.MoveBetweenSets(fromkey, tokey, value);
        }
        /// <summary>
        /// 返回keys多个集合中的并集,返还hashset
        /// </summary>
        public HashSet<string> GetUnionFromSets(params string[] keys)
        {
            return base.iClient.GetUnionFromSets(keys);
        }
        /// <summary>
        /// 返回keys多个集合中的交集,返还hashset
        /// </summary>
        public HashSet<string> GetIntersectFromSets(params string[] keys)
        {
            return base.iClient.GetIntersectFromSets(keys);
        }
        /// <summary>
        /// 返回keys多个集合中的差集,返还hashset
        /// </summary>
        /// <param name="fromKey">原集合</param>
        /// <param name="keys">其他集合</param>
        /// <returns>出现在原集合,但不包含在其他集合</returns>
        public HashSet<string> GetDifferencesFromSet(string fromKey, params string[] keys)
        {
            return base.iClient.GetDifferencesFromSet(fromKey,keys);
        }
        /// <summary>
        /// keys多个集合中的并集,放入newkey集合中
        /// </summary>
        public void StoreUnionFromSets(string newkey, string[] keys)
        {
            base.iClient.StoreUnionFromSets(newkey, keys);
        }
        /// <summary>
        /// 把fromkey集合中的数据与keys集合中的数据对比,fromkey集合中不存在keys集合中,则把这些不存在的数据放入newkey集合中
        /// </summary>
        public void StoreDifferencesFromSet(string newkey, string fromkey, string[] keys)
        {
            base.iClient.StoreDifferencesFromSet(newkey, fromkey, keys);
        }
        #endregion
    }

 

 一些简单的api方法:

      using (RedisSetService service = new RedisSetService())
                {
                    service.FlushAll();//清理全部数据

                    service.Add("advanced", "111");
                    service.Add("advanced", "112");
                    service.Add("advanced", "114");
                    service.Add("advanced", "114");
                    service.Add("advanced", "115");
                    service.Add("advanced", "115");
                    service.Add("advanced", "113");

                    var result = service.GetAllItemsFromSet("advanced");
                    //随机获取key其中一个value
                    var random = service.GetRandomItemFromSet("advanced");
                    service.GetCount("advanced");//独立的ip数
                    //删除指定数据
                    service.RemoveItemFromSet("advanced", "114");

                    {
                        service.Add("begin", "111");
                        service.Add("begin", "112");
                        service.Add("begin", "115");

                        service.Add("end", "111");
                        service.Add("end", "114");
                        service.Add("end", "113");
                        //获取begin和end中的 交集
                        var result1 = service.GetIntersectFromSets("begin", "end");
                        //获取begin和end中的 差集
                        var result2 = service.GetDifferencesFromSet("begin", "end");
                        //获取begin和end中的 并集,就是2者
                        var result3 = service.GetUnionFromSets("begin", "end");
                        //共同好友   共同关注
                    }
                }

  set存储的格式:

 下面列举了一个添加好友的一个例子:

     public static void Show()
        {
            using (RedisSetService service = new RedisSetService())
            {
                service.FlushAll();
                service.Add("Richard", "云怀");
                service.Add("Richard", "fresh");
                service.Add("Richard", "腾坤");
                service.Add("Richard", "心有所属");
                service.Add("Richard", "莎士比亚");

                service.Add("fresh", "奥利给");
                service.Add("fresh", "明日梦");
                service.Add("fresh", "棒棒糖");
                service.Add("fresh", "放下");
                service.Add("fresh", "阳光下的微信");
                service.Add("fresh", "腾坤");
                //1.查询共同好友; 求交集
                var resut1 = service.GetIntersectFromSets("Richard", "fresh");//
                //2.好友推荐/可能认识人,这是给Richard推荐的  返回keys多个集合中的差集,返还hashset 出现在fresh集合中,但不包含在Richard集合中
                var resut2 = service.GetDifferencesFromSet("fresh", "Richard");
                //同上
                var resut3 = service.GetDifferencesFromSet("Richard", "fresh");//
                //汇总所有的  并集
                var result4 = service.GetUnionFromSets("Richard", "fresh");

            }

        }

 

 ZSet存储

 

可以去重复还可以排序。比如排行榜的时候可以使用!

封装的一些常用的api类:

 /// <summary>
    /// Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列
    /// 1.带有权重的元素,比如一个游戏的用户得分排行榜
    /// 2.比较复杂的数据结构,一般用到的场景不算太多
    /// </summary>
    public class RedisZSetService : RedisBase
    {
        #region 添加
        /// <summary>
        /// 添加key/value,默认分数是从1.多*10的9次方以此递增的,自带自增效果
        /// </summary>
        public bool Add(string key, string value)
        {
            return base.iClient.AddItemToSortedSet(key, value);
        }
        /// <summary>
        /// 添加key/value,并设置value的分数
        /// </summary>
        public bool AddItemToSortedSet(string key, string value, double score)
        {
            return base.iClient.AddItemToSortedSet(key, value, score);
        }
        /// <summary>
        /// 为key添加values集合,values集合中每个value的分数设置为score
        /// </summary>
        public bool AddRangeToSortedSet(string key, List<string> values, double score)
        {
            return base.iClient.AddRangeToSortedSet(key, values, score);
        }
        /// <summary>
        /// 为key添加values集合,values集合中每个value的分数设置为score
        /// </summary>
        public bool AddRangeToSortedSet(string key, List<string> values, long score)
        {
            return base.iClient.AddRangeToSortedSet(key, values, score);
        }
        #endregion

        #region 获取
        /// <summary>
        /// 获取key的所有集合
        /// </summary>
        public List<string> GetAll(string key)
        {
            return base.iClient.GetAllItemsFromSortedSet(key);
        }
        /// <summary>
        /// 获取key的所有集合,倒叙输出
        /// </summary>
        public List<string> GetAllDesc(string key)
        {
            return base.iClient.GetAllItemsFromSortedSetDesc(key);
        }
        /// <summary>
        /// 获取集合,带分数
        /// </summary>
        public IDictionary<string, double> GetAllWithScoresFromSortedSet(string key)
        {
            return base.iClient.GetAllWithScoresFromSortedSet(key);
        }
        /// <summary>
        /// 获取key为value的下标值
        /// </summary>
        public long GetItemIndexInSortedSet(string key, string value)
        {
            return base.iClient.GetItemIndexInSortedSet(key, value);
        }
        /// <summary>
        /// 倒叙排列获取key为value的下标值
        /// </summary>
        public long GetItemIndexInSortedSetDesc(string key, string value)
        {
            return base.iClient.GetItemIndexInSortedSetDesc(key, value);
        }
        /// <summary>
        /// 获取key为value的分数
        /// </summary>
        public double GetItemScoreInSortedSet(string key, string value)
        {
            return base.iClient.GetItemScoreInSortedSet(key, value);
        }
        /// <summary>
        /// 获取key所有集合的数据总数
        /// </summary>
        public long GetSortedSetCount(string key)
        {
            return base.iClient.GetSortedSetCount(key);
        }
        /// <summary>
        /// key集合数据从分数为fromscore到分数为toscore的数据总数
        /// </summary>
        public long GetSortedSetCount(string key, double fromScore, double toScore)
        {
            return base.iClient.GetSortedSetCount(key, fromScore, toScore);
        }
        /// <summary>
        /// 获取key集合从高分到低分排序数据,分数从fromscore到分数为toscore的数据
        /// </summary>
        public List<string> GetRangeFromSortedSetByHighestScore(string key, double fromscore, double toscore)
        {
            return base.iClient.GetRangeFromSortedSetByHighestScore(key, fromscore, toscore);
        }
        /// <summary>
        /// 获取key集合从低分到高分排序数据,分数从fromscore到分数为toscore的数据
        /// </summary>
        public List<string> GetRangeFromSortedSetByLowestScore(string key, double fromscore, double toscore)
        {
            return base.iClient.GetRangeFromSortedSetByLowestScore(key, fromscore, toscore);
        }
        /// <summary>
        /// 获取key集合从高分到低分排序数据,分数从fromscore到分数为toscore的数据,带分数
        /// </summary>
        public IDictionary<string, double> GetRangeWithScoresFromSortedSetByHighestScore(string key, double fromscore, double toscore)
        {
            return base.iClient.GetRangeWithScoresFromSortedSetByHighestScore(key, fromscore, toscore);
        }
        /// <summary>
        ///  获取key集合从低分到高分排序数据,分数从fromscore到分数为toscore的数据,带分数
        /// </summary>
        public IDictionary<string, double> GetRangeWithScoresFromSortedSetByLowestScore(string key, double fromscore, double toscore)
        {
            return base.iClient.GetRangeWithScoresFromSortedSetByLowestScore(key, fromscore, toscore);
        }
        /// <summary>
        ///  获取key集合数据,下标从fromRank到分数为toRank的数据
        /// </summary>
        public List<string> GetRangeFromSortedSet(string key, int fromRank, int toRank)
        {
            return base.iClient.GetRangeFromSortedSet(key, fromRank, toRank);
        }
        /// <summary>
        /// 获取key集合倒叙排列数据,下标从fromRank到分数为toRank的数据
        /// </summary>
        public List<string> GetRangeFromSortedSetDesc(string key, int fromRank, int toRank)
        {
            return base.iClient.GetRangeFromSortedSetDesc(key, fromRank, toRank);
        }
        /// <summary>
        /// 获取key集合数据,下标从fromRank到分数为toRank的数据,带分数
        /// </summary>
        public IDictionary<string, double> GetRangeWithScoresFromSortedSet(string key, int fromRank, int toRank)
        {
            return base.iClient.GetRangeWithScoresFromSortedSet(key, fromRank, toRank);
        }
        /// <summary>
        ///  获取key集合倒叙排列数据,下标从fromRank到分数为toRank的数据,带分数
        /// </summary>
        public IDictionary<string, double> GetRangeWithScoresFromSortedSetDesc(string key, int fromRank, int toRank)
        {
            return base.iClient.GetRangeWithScoresFromSortedSetDesc(key, fromRank, toRank);
        }
        #endregion

        #region 删除
        /// <summary>
        /// 删除key为value的数据
        /// </summary>
        public bool RemoveItemFromSortedSet(string key, string value)
        {
            return base.iClient.RemoveItemFromSortedSet(key, value);
        }
        /// <summary>
        /// 删除下标从minRank到maxRank的key集合数据
        /// </summary>
        public long RemoveRangeFromSortedSet(string key, int minRank, int maxRank)
        {
            return base.iClient.RemoveRangeFromSortedSet(key, minRank, maxRank);
        }
        /// <summary>
        /// 删除分数从fromscore到toscore的key集合数据
        /// </summary>
        public long RemoveRangeFromSortedSetByScore(string key, double fromscore, double toscore)
        {
            return base.iClient.RemoveRangeFromSortedSetByScore(key, fromscore, toscore);
        }
        /// <summary>
        /// 删除key集合中分数最大的数据
        /// </summary>
        public string PopItemWithHighestScoreFromSortedSet(string key)
        {
            return base.iClient.PopItemWithHighestScoreFromSortedSet(key);
        }
        /// <summary>
        /// 删除key集合中分数最小的数据
        /// </summary>
        public string PopItemWithLowestScoreFromSortedSet(string key)
        {
            return base.iClient.PopItemWithLowestScoreFromSortedSet(key);
        }
        #endregion

        #region 其它
        /// <summary>
        /// 判断key集合中是否存在value数据
        /// </summary>
        public bool SortedSetContainsItem(string key, string value)
        {
            return base.iClient.SortedSetContainsItem(key, value);
        }
        /// <summary>
        /// 为key集合值为value的数据,分数加scoreby,返回相加后的分数
        /// </summary>
        public double IncrementItemInSortedSet(string key, string value, double scoreBy)
        {
            return base.iClient.IncrementItemInSortedSet(key, value, scoreBy);
        }
        /// <summary>
        /// 获取keys多个集合的交集,并把交集添加的newkey集合中,返回交集数据的总数
        /// </summary>
        public long StoreIntersectFromSortedSets(string newkey, string[] keys)
        {
            return base.iClient.StoreIntersectFromSortedSets(newkey, keys);
        }
        /// <summary>
        /// 获取keys多个集合的并集,并把并集数据添加到newkey集合中,返回并集数据的总数
        /// </summary>
        public long StoreUnionFromSortedSets(string newkey, string[] keys)
        {
            return base.iClient.StoreUnionFromSortedSets(newkey, keys);
        }
        #endregion
    }

 

简单调用对应的一些常用api:

                using (RedisZSetService service = new RedisZSetService())
                {
                    service.FlushAll();//清理全部数据
                    //添加之后会默认一个score,默认递增
                    service.Add("advanced", "1");
                    service.Add("advanced", "2");
                    service.Add("advanced", "5");
                    service.Add("advanced", "4");
                    service.Add("advanced", "7");
                    service.Add("advanced", "5");
                    service.Add("advanced", "9");

                    var result1 = service.GetAll("advanced");
                    //获取key为advanced的集合信息,倒序输出
                    var result2 = service.GetAllDesc("advanced");
                    //也可以手动指定score值,默认按照score值递增
                    service.AddItemToSortedSet("Sort", "BY", 123234);
                    service.AddItemToSortedSet("Sort", "走自己的路", 123);
                    service.AddItemToSortedSet("Sort", "redboy", 45);
                    service.AddItemToSortedSet("Sort", "大蛤蟆", 7567);
                    service.AddItemToSortedSet("Sort", "路人甲", 9879);
                    var result3 = service.GetAllWithScoresFromSortedSet("Sort");

                    //交叉并
                }

 

  redis可视化工具中查看到的数据:

 

 

 

接下来模拟一个排行榜的场景,比如一个直播间中的观众的礼物排行榜,这东西是实时的刷新的,不能一直来刷新数据库,所以可以用redis,并且使用zset来存储:

 

    /// <summary>
    /// 直播平台:很多频道---不同的房间/主播
    ///           刷小礼物!
    ///            
    /// 排行榜:频道排行!平台的排行!房间排行榜!  需要实时展示数据!
    /// Redis--Zset;排序
    /// 
    /// </summary>
    public class RankManager
    {

        //模拟的房间的听众
        private static List<string> userList = new List<string>()
        {
            "棒棒糖","苏洋","思索","奥利给","Alex","君临天下"
        };

        public static void Show()
        {
            using (RedisZSetService service = new RedisZSetService())
            {
                service.FlushAll();
                Task.Run(() => //刷礼物---每隔2秒钟就刷一个礼物
                {
                    while (true)
                    {
                        foreach (var user in userList)
                        {
                            Thread.Sleep(20);
                            //设置 刷礼物的人,每次刷的礼物是1到100之间的一个随机数
                            service.IncrementItemInSortedSet("主播1", user, new Random().Next(1, 100));
                        }
                        Thread.Sleep(20 * 100);
                    }
                });
                //实时展示排行榜 每5秒展示一次最新数据
                Task.Run(() =>
                {
                    while (true)
                    {
                        Console.WriteLine("**************Eleven房间排行榜******************");
                        Thread.Sleep(5 * 1000);
                        //获取主播1中所有刷礼物的人的信息
                        var dic = service.GetAllWithScoresFromSortedSet("主播1");
                        int i = 1;
                        foreach (var item in dic)
                        {
                            Console.WriteLine($"第{i++}名   {item.Key} 分数{item.Value}");
                        }
                    }
                });
                Console.Read();

              
            }

        }
    }

 

 

 

 

 

 

 

a

posted @ 2021-10-08 16:37  安静点--  阅读(245)  评论(0编辑  收藏  举报