一,、Redis API For .Net首先,不得不說Redis官方提供了眾多的API開發(fā)包,,但是目前Redis官方版本不支持.Net直接進行連接,,需要使用一些第三方的開源類庫。目前最流行的就是ServiceStack.Redis這個開源項目,,其在GitHub上的下載地址為:https://github.com/ServiceStack/ServiceStack.Redis
進入下載頁面,,點擊“Download Zip”按鈕,即可下載該API包,。解壓該Zip包后,,其實我們所用到的只是其中的幾個DLL而已,打開build/release/MonoDevelop文件夾,,看到里邊還有一個zip包,,這里邊就是我們所需的DLL了。
再次解壓這個Zip包,,可以看到其中包含如下圖所示的DLL文件,,這幾個也是我們今天所要引入VS的DLL庫,有了它們,,我們就可以在程序端和Redis服務(wù)端進行對話了,,是不是很贊?
這時,,我們就可以在VS中新建一個控制臺項目,,命名為RedisDemo,然后新建一個Lib文件夾用來存放我們的DLL文件,,然后添加對這些DLL引用,。至此,就是萬事俱備只欠東風(fēng)了,,我們接下來會在程序中調(diào)用Redis客戶端和Redis服務(wù)端進行通信,,了解Redis API為我們提供的豐富的數(shù)據(jù)類型。
二,、Redis中常用數(shù)據(jù)類型由上一篇博客可知,,Redis目前提供五種數(shù)據(jù)類型:string(字符串)、list(鏈表)、Hash(哈希),、set(集合)及zset(sorted set) (有序集合)?,F(xiàn)在,我們一一來看看這五種數(shù)據(jù)類型的基本使用方法,。在開始介紹之前,我們先使用剛剛引入的Redis API建立一個Redis客戶端對象,,有了這個客戶端對象,,我們才能和Redis服務(wù)端進行通信,且看下面的一行代碼,。我們需要事先指定好Redis服務(wù)端的IP地址和端口號,,然后根據(jù)這兩個信息建立一個RedisClient的對象實例,通過這個實例所帶的方法和服務(wù)端通信,。 using System; using System.Collections.Generic; using ServiceStack.Redis; namespace RedisDemo.FirstStart { class Program { //Redis服務(wù)器IP地址 static string localHostIP = "127.0.0.1"; //Redis服務(wù)端口號 static int redisServicePort = 6379; static void Main(string[] args) { var redisClient = new RedisClient(localHostIP, redisServicePort); Console.ReadKey(); } } } 2.1 String 字符串String是最常用的一種數(shù)據(jù)類型,,普通的key/value存儲都可以歸為此類 。一個Key對應(yīng)一個Value,,string類型是二進制安全的,。Redis的string可以包含任何數(shù)據(jù),比如jpg圖片(生成二進制)或者序列化的對象,。 在Redis中的基本操作如下所示: static void StringTypeDemo(RedisClient redisClient) { //向Redis中添加一個Key/Value對 redisClient.Set<string>("username", "edisonchou"); //從Redis中讀取一個Value值 string userName = redisClient.Get<string>("username"); Console.WriteLine("The value from Redis is {0}", userName); } 運行效果如下: 2.2 Hash 哈希 Hash是一個string 類型的field和value的映射表,。Hash特別適合存儲對象,相對于將對象的每個字段存成單個string 類型,。一個對象存儲在Hash類型中會占用更少的內(nèi)存,,并且可以更方便的存取整個對象。
這里借用群叔的描述,,我們簡單舉個實例來描述下Hash的應(yīng)用場景,,比如我們要存儲一個用戶信息對象數(shù)據(jù),包含以下信息:用戶ID為查找的key,,存儲的value用戶對象包含姓名,,年齡,生日等信息,,如果用普通的key/value結(jié)構(gòu)來存儲,,主要有以下2種存儲方式:
第一種方式將用戶ID作為查找key,把其他信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是,,增加了序列化/反序列化的開銷,,并且在需要修改其中一項信息時,需要把整個對象取回,,并且修改操作需要對并發(fā)進行保護,,引入CAS等復(fù)雜問題。
第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶ID+對應(yīng)屬性的名稱作為唯一標(biāo)識來取得對應(yīng)屬性的值,,雖然省去了序列化開銷和并發(fā)問題,,但是用戶ID為重復(fù)存儲,如果存在大量這樣的數(shù)據(jù),,內(nèi)存浪費還是非??捎^的。
因此,,基于以上兩種方式的缺陷,,Redis提供的Hash很好的解決了這個問題,Redis的Hash實際是內(nèi)部存儲的Value為一個HashMap,,并提供了直接存取這個Map成員的接口,,如下圖:
也就是說,Key仍然是用戶ID, value是一個Map,,這個Map的key是成員的屬性名,,value是屬性值,這樣對數(shù)據(jù)的修改和存取都可以直接通過其內(nèi)部Map的Key(Redis里稱內(nèi)部Map的key為field), 也就是通過key(用戶ID) + field(屬性標(biāo)簽) 就可以操作對應(yīng)屬性數(shù)據(jù)了,,既不需要重復(fù)存儲數(shù)據(jù),,也不會帶來序列化和并發(fā)修改控制的問題,也就很好的解決了問題,。
下面我們在VS中來看看Hash類型如何Code:
static void HashTypeDemo(RedisClient redisClient) { redisClient.SetEntryInHash("user", "userinfo", "cool boy"); redisClient.SetEntryInHash("user", "useraccount", "5000"); List<string> keyList = redisClient.GetHashKeys("user"); foreach (string key in keyList) { Console.WriteLine(key); string value = redisClient.GetValueFromHash("user", key); Console.WriteLine("user:{0}:{1}", key, value); } } 運行結(jié)果如下圖:
2.3 List 鏈表Lst是一個鏈表結(jié)構(gòu),,主要功能是push與pop,獲取一個范圍的所有的值等,,操作中key理解為鏈表名字,。 Redis的List類型其實就是一個每個子元素都是string類型的雙向鏈表,我們可以通過push或pop操作從鏈表的頭部或者尾部添加刪除元素,,這樣List既可以作為棧,,又可以作為隊列。它即可以支持反向查找和遍歷,,更方便操作,,不過帶來了部分額外的內(nèi)存開銷。Redis內(nèi)部的很多實現(xiàn),,包括發(fā)送緩沖隊列等也都是用的這個數(shù)據(jù)結(jié)構(gòu),。 (1)現(xiàn)在我們首先來看看List作為(Stack)棧類型的使用:
那么在VS中如何來Code呢,?通過Push與Pop操作Stack static void StackTypeDemo(RedisClient redisClient) { redisClient.PushItemToList("userenname", "edisonchou"); redisClient.PushItemToList("userenname", "wncudchou"); redisClient.PushItemToList("userenname", "milkye"); redisClient.PushItemToList("userenname", "dickgu"); int length = redisClient.GetListCount("userenname"); for (int i = 0; i < length; i++) { Console.WriteLine(redisClient.PopItemFromList("userenname")); } } 運行效果如下: ?。?)下面我們來看看List作為(Queue)隊列的使用: 那么在VS中如何Code呢?通過DeQueue和EnQueue操作Queue static void QueueTypeDemo(RedisClient redisClient) { redisClient.EnqueueItemOnList("account", "馬云"); redisClient.EnqueueItemOnList("account", "馬化騰"); redisClient.EnqueueItemOnList("account", "李彥宏"); int length = redisClient.GetListCount("account"); for (int i = 0; i < length; i++) { Console.WriteLine(redisClient.DequeueItemFromList("account")); } } 運行效果如下: 2.4 Set 集合Set是string類型的無序集合,。set是通過hash table實現(xiàn)的,,添加,刪除和查找,對集合我們可以取并集,,交集,,差集,可以非常方便的實現(xiàn)如共同關(guān)注,、共同喜好,、二度好友等功能,對上面的所有集合操作,,你還可以使用不同的命令選擇將結(jié)果返回給客戶端還是存集到一個新的集合中,。 與List比較而言,set對外提供的功能與list類似是一個列表的功能,,特殊之處在于set是可以自動排重的,當(dāng)你需要存儲一個列表數(shù)據(jù),,又不希望出現(xiàn)重復(fù)數(shù)據(jù)時,,set是一個很好的選擇,并且set提供了判斷某個成員是否在一個set集合內(nèi)的重要接口,,這個也是list所不能提供的,。 那么在VS中我們使用Set來Code一下,先增加兩個Set集合,,然后對其進行交集,、并集與差集運算: static void SetTypeDemo(RedisClient redisClient) { redisClient.AddItemToSet("a3", "ddd"); redisClient.AddItemToSet("a3", "ccc"); redisClient.AddItemToSet("a3", "tttt"); redisClient.AddItemToSet("a3", "sssh"); redisClient.AddItemToSet("a3", "hhhh"); redisClient.AddItemToSet("a4", "hhhh"); redisClient.AddItemToSet("a4", "h777"); Console.WriteLine("-------------求a3集合------------"); HashSet<string> hashSet = redisClient.GetAllItemsFromSet("a3"); foreach (string value in hashSet) { Console.WriteLine(value); } Console.WriteLine("-------------求并集------------"); hashSet.Clear(); hashSet = redisClient.GetUnionFromSets(new string[] { "a3", "a4" }); foreach (string value in hashSet) { Console.WriteLine(value); } Console.WriteLine("-------------求交集------------"); hashSet.Clear(); hashSet = redisClient.GetIntersectFromSets(new string[] { "a3", "a4" }); foreach (string value in hashSet) { Console.WriteLine(value); } Console.WriteLine("-------------求差集------------"); hashSet.Clear(); hashSet = redisClient.GetDifferencesFromSet("a3", new string[] { "a4" }); foreach (string value in hashSet) { Console.WriteLine(value); } } 運行效果如下: 2.5 Sorted Set 有序集合 Sorted Set 是set的一個升級版本,又被稱為ZSet,,它在set的基礎(chǔ)上增加了一個順序的屬性,,這一屬性在添加修改。元素的時候可以指定,,每次指定后,,zset(表示有序集合)會自動重新按新的值調(diào)整順序。可以理解為有列的表,,一列存 value,,一列存順序。操作中key理解為zset的名字,。
sorted set的使用場景與set類似,,區(qū)別是set不是自動有序的,而sorted set可以通過用戶額外提供一個優(yōu)先級(score)的參數(shù)來為成員排序,,并且是插入有序的,,即自動排序。當(dāng)你需要一個有序的并且不重復(fù)的集合列表,,那么可以選擇sorted set數(shù)據(jù)結(jié)構(gòu),。此外,還可以用Sorted Sets來做帶權(quán)重的隊列,比如普通消息的score為1,,重要消息的score為2,,然后工作線程可以選擇按score的倒序來獲取工作任務(wù)。讓重要的任務(wù)優(yōu)先執(zhí)行,。
下面,,我們在VS中編寫對Sorted Set的操作代碼,輸出時會按字母的有序順序輸出:
static void SortedSetTypeDemo(RedisClient redisClient) { redisClient.AddItemToSortedSet("a5", "ffff"); redisClient.AddItemToSortedSet("a5", "bbbb"); redisClient.AddItemToSortedSet("a5", "gggg"); redisClient.AddItemToSortedSet("a5", "cccc"); redisClient.AddItemToSortedSet("a5", "waaa"); List<string> list = redisClient.GetAllItemsFromSortedSet("a5"); foreach (string str in list) { Console.WriteLine(str); } } 運行效果如下: 三,、小結(jié)Redis為我們提供了相比Memcached更為豐富多樣的數(shù)據(jù)類型,,使得Redis可以用在多種多樣的應(yīng)用場合,這也說明了為什么Redis在國內(nèi)外各大互聯(lián)網(wǎng)名企中這么受歡迎的原因,。本篇簡單地介紹和使用了各種數(shù)據(jù)類型,,下一篇,我們會針對1-2個具體應(yīng)用場景來使用這些數(shù)據(jù)類型進行具體案例的Code,。最后,,還是謝謝參考資料的原作者,站在你們的肩膀上,,我們才能看的更遠,! 參考文獻(1)傳智播客公開課,王承偉主講,,http://bbs./thread-26525-1-1.html (2)群叔,,《Redis數(shù)據(jù)類型詳解及Redis適用場景》,http://www.cnblogs.com/qunshu/p/3196972.html 附件下載(1)ServiceStack.Redis:http://pan.baidu.com/s/1sjtxe5v |
|