NoSQL初探之人人都愛Redis:(2)Redis API與常用數據類型簡介


一、Redis API For .Net

  首先,不得不說Redis官方提供了眾多的API開發包,但是目前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服務端進行對話了,是不是很贊?

  這時,我們就可以在VS中新建一個控制台項目,命名為RedisDemo,然后新建一個Lib文件夾用來存放我們的DLL文件,然后添加對這些DLL引用。至此,就是萬事俱備只欠東風了,我們接下來會在程序中調用Redis客戶端和Redis服務端進行通信,了解Redis API為我們提供的豐富的數據類型。

二、Redis中常用數據類型

  由上一篇博客可知,Redis目前提供五種數據類型:string(字符串)、list(鏈表)、Hash(哈希)、set(集合)及zset(sorted set)  (有序集合)。現在,我們一一來看看這五種數據類型的基本使用方法。在開始介紹之前,我們先使用剛剛引入的Redis API建立一個Redis客戶端對象,有了這個客戶端對象,我們才能和Redis服務端進行通信,且看下面的一行代碼。我們需要事先指定好Redis服務端的IP地址和端口號,然后根據這兩個信息建立一個RedisClient的對象實例,通過這個實例所帶的方法和服務端通信。

using System;
using System.Collections.Generic;
using ServiceStack.Redis;

namespace RedisDemo.FirstStart
{
    class Program
    {
        //Redis服務器IP地址
        static string localHostIP = "127.0.0.1";
        //Redis服務端口號
        static int redisServicePort = 6379;           

        static void Main(string[] args)
        {
            var redisClient = new RedisClient(localHostIP, redisServicePort);

            Console.ReadKey();
        }
    }
}

  2.1 String 字符串

  String是最常用的一種數據類型,普通的key/value存儲都可以歸為此類 。一個Key對應一個Value,string類型是二進制安全的。Redis的string可以包含任何數據,比如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類型中會占用更少的內存,並且可以更方便的存取整個對象。
  這里借用 群叔的描述,我們簡單舉個實例來描述下Hash的應用場景,比如我們要存儲一個用戶信息對象數據,包含以下信息:用戶ID為查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,如果用普通的key/value結構來存儲,主要有以下2種存儲方式:
  第一種方式將用戶ID作為查找key,把其他信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是, 增加了序列化/反序列化的開銷,並且在需要修改其中一項信息時,需要把整個對象取回,並且修改操作需要對並發進行保護,引入CAS等復雜問題。
  第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶ID+對應屬性的名稱作為唯一標識來取得對應屬性的值,雖然省去了序列化開銷和並發問題,但是用戶ID為重復存儲,如果存在大量這樣的數據, 內存浪費還是非常可觀的
  因此,基於以上兩種方式的缺陷,Redis提供的Hash很好的解決了這個問題, Redis的Hash實際是內部存儲的Value為一個HashMap,並提供了直接存取這個Map成員的接口,如下圖:
  也就是說,Key仍然是用戶ID, value是一個Map,這個Map的key是成員的屬性名,value是屬性值,這樣對數據的修改和存取都可以直接通過其內部Map的Key(Redis里稱內部Map的key為field), 也就是通過 key(用戶ID) + field(屬性標簽) 就可以操作對應屬性數據了,既不需要重復存儲數據,也不會帶來序列化和並發修改控制的問題,也就很好的解決了問題。
  下面我們在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);
            }
        }
  運行結果如下圖:

  2.3 List 鏈表

  Lst是一個鏈表結構,主要功能是push與pop,獲取一個范圍的所有的值等,操作中key理解為鏈表名字。 Redis的List類型其實就是一個每個子元素都是string類型的雙向鏈表,我們可以通過push或pop操作從鏈表的頭部或者尾部添加刪除元素,這樣List既可以作為棧,又可以作為隊列。它即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷。Redis內部的很多實現,包括發送緩沖隊列等也都是用的這個數據結構。

  (1)現在我們首先來看看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"));
            }
        }

  運行效果如下:

  (2)下面我們來看看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實現的,添加,刪除和查找,對集合我們可以取並集,交集,差集,可以非常方便的實現如共同關注、共同喜好、二度好友等功能,對上面的所有集合操作,你還可以使用不同的命令選擇將結果返回給客戶端還是存集到一個新的集合中。

  與List比較而言,set對外提供的功能與list類似是一個列表的功能,特殊之處在於set是可以自動排重的,當你需要存儲一個列表數據,又不希望出現重復數據時,set是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的重要接口,這個也是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的基礎上增加了一個順序的屬性,這一屬性在添加修改。元素的時候可以指定,每次指定后,zset(表示有序集合)會自動重新按新的值調整順序。 可以理解為有列的表,一列存 value,一列存順序。操作中key理解為zset的名字。
  sorted set的使用場景與set類似,區別是 set不是自動有序的,而sorted set可以通過用戶額外提供一個優先級(score)的參數來為成員排序,並且是插入有序的,即自動排序。 當你需要一個有序的並且不重復的集合列表,那么可以選擇sorted set數據結構此外,還可以用Sorted Sets來做帶權重的隊列,比如普通消息的score為1,重要消息的score為2,然后工作線程可以選擇按score的倒序來獲取工作任務。讓重要的任務優先執行。
  下面,我們在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);
            }
        }

  運行效果如下:

三、小結

  Redis為我們提供了相比Memcached更為豐富多樣的數據類型,使得Redis可以用在多種多樣的應用場合,這也說明了為什么Redis在國內外各大互聯網名企中這么受歡迎的原因。本篇簡單地介紹和使用了各種數據類型,下一篇,我們會針對1-2個具體應用場景來使用這些數據類型進行具體案例的Code。最后,還是謝謝參考資料的原作者,站在你們的肩膀上,我們才能看的更遠!

參考文獻

(1)傳智播客公開課,王承偉主講,http://bbs.itcast.cn/thread-26525-1-1.html

(2)群叔,《Redis數據類型詳解及Redis適用場景》,http://www.cnblogs.com/qunshu/p/3196972.html

附件下載

(1)ServiceStack.Redis:http://pan.baidu.com/s/1sjtxe5v

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM