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();

                //現在大家開始提問,22:20  開始答疑! 期間老師就不說話了!
            }

        }
    }

轉載:

https://www.cnblogs.com/anjingdian/p/15380530.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章