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