一.前言
redis並不是簡單的key-value資料容器,不能將其理解為靜態儲存資料,它是動態互動的資料結構伺服器,可以被用作緩衝,高效能k-v資料庫等。
它支援很多種類型的資料結構,不僅支援string類型的value,還支援很多種複雜類型的資料。以下簡單列出redis支援的資料類型,後續再對每種資料類型以及它們的常用操作命令做詳細介紹
1.安全二進位氏String類型:將String類型作為元素值;
2.Lists類型:根據插入順序的String類型為元素的集合,基於Linked List實現,非Array型;
3.Sets類型:無重複且無序的String類型為元素的集合;
4.Sorted Set類型:無重複且有序的String類型為元素的集合;
5.Hashes類型:映射域到實值型別的資料結構,其中域和值都是String類型;
二.Redis資料類型詳解
在介紹資料類型之前,先讓我們來看看Redis k-v資料結構中非常重要的key形式。redis中的key是二進位安全的也就是說任何二進位序列都可以作為key,譬如:字串“foo”,一張圖片的內容等。甚至Null 字元串都可以。
良好的key的命名規則如下:
1.key不要太長。在redis中可以的最大容量是512M,但是實際中key超過1024byte就非良好的設計方式了。key值太大不僅浪費記憶體空間,更是在請求中對於key'的尋找需要更多的時間進行比較;
2.key值不宜太短。這個原則貌似與第一條相衝突,實則不然。有時key的變長使得增加空間相對於使得key更具可讀性更顯次要;
3.key的命名中可以使用冒號和破折號加以細分,使key更具可讀性,靈活性。例如:aticle:1000:tags。其中第一位表示類型,第二位表示該類型對象的Id,第三位表示Id為1000的文章中的標記;
作用於Key的常用命令:
redis提供很多非常實用而有效命令,這些命令作用於redis中的Key,管理Key的空間。
1.EXISTS
exists主要是尋找指定的鍵是否存在,如果存在則返回(Integer) 1,否則返回(Integer) 0。使用方式如下:
首先實用redis-cli命令進入redis的用戶端命令列模式:
127.0.0.1:6379> SET mystring "mystring0"OK127.0.0.1:6379> GET mystring"mystring0"127.0.0.1:6379> EXISTS mystring(integer) 1127.0.0.1:6379> EXISTS mystring1(integer) 0127.0.0.1:6379>
2.DEL
del主要用來刪除Key,並將Key對應的值隨之刪除。
127.0.0.1:6379> EXISTS mystring(integer) 1127.0.0.1:6379> 127.0.0.1:6379> DEL mystring(integer) 1127.0.0.1:6379> EXISTS mystring(integer) 0127.0.0.1:6379> GET mystring(nil)127.0.0.1:6379>
3 .EXPIRE
expire設定Key的有效期間,如果超過設定的存活時間,Key將自動失效並隨之刪除。與之相反的命令PERSIST使Key永久有效,與之協作的命令TTL查看Key剩餘有效時間。
127.0.0.1:6379> SET mystring1 "string1"OK127.0.0.1:6379> EXISTS mystring1(integer) 1127.0.0.1:6379> EXPIRE mystring1 10000(integer) 1127.0.0.1:6379> GET mystring1"string1"127.0.0.1:6379> TTL mystring1(integer) 9976127.0.0.1:6379> TTL mystring1(integer) 9975127.0.0.1:6379> TTL mystring1
127.0.0.1:6379> 127.0.0.1:6379> SET mystring2 "string2"OK127.0.0.1:6379> EXPIRE mystring2 20(integer) 1127.0.0.1:6379> 127.0.0.1:6379> GET mystring2"string2"127.0.0.1:6379> TTL mystring2(integer) 6127.0.0.1:6379> TTL mystring2(integer) 5127.0.0.1:6379> TTL mystring2(integer) 2127.0.0.1:6379> TTL mystring2(integer) 1127.0.0.1:6379> GET mystring2(nil)127.0.0.1:6379>
redis中Value的資料類型
Sting類型 先讓我們來看看String類型吧。String類型是redis中最單一資料型別,String類型實質是一個String映射到另一個String,同時它也是複雜類型的基底類型。String類型的value不得超過512M,可以被使用在很多場合,例如:快取頁面面。
127.0.0.1:6379> SET mystring7 string7OK127.0.0.1:6379> GET mystring7"string7"127.0.0.1:6379> SET mystring8 "string8"OK127.0.0.1:6379> GET mystring8"string8"
從以上命令中可以看到GET返回的值是String類型,且SET命令中的value參數可以含有雙引號也不含有。SET和GET命令是設定和擷取String類型的基本命令,且它們可以附加參數,但這裡不加以討論其命令,在稍後的章節中再詳細介紹命令的使用詳情。
如果String類型的值是數字類型,則可以使用加法和減法操作,在使用算術運算的時候,其實redis將其String類型解析成Integer類型進行運算的。讓我們來看看接下來的例子:
127.0.0.1:6379> SET mystring12 100OK127.0.0.1:6379> INCR mystring12(integer) 101127.0.0.1:6379> GET mystring12"101"127.0.0.1:6379> INCRBY mystring12 35(integer) 136127.0.0.1:6379> GET mystring12"136"127.0.0.1:6379> DECR mystring12(integer) 135127.0.0.1:6379> GET mystring12"135"127.0.0.1:6379> DECRBY mystring12 200(integer) -65127.0.0.1:6379> GET mystring12"-65"
String類型非常簡單,我們就介紹的這裡。以後介紹命令時候再進行補充。
Lists類型 Lists類型一般實現有常見的兩種: 1.基於Arrays線性數組實現的List資料結構 2.基於Linked List鏈式節點實現的List資料結構 在每種應用中的實現都是差不多遵循這樣的思想,如:java的ArrayList和LinkedList、c語言資料結構的線性鏈表和鏈式鏈表;同樣redis中也遵循這樣的思想。但是redis中的Lists則採用的是第二種演算法。LinkedList的實現決定了它有高效能的插入刪除操作,而Arrays型List效能在於查詢擷取。 因為相對於緩衝或者資料庫系統而言,在插入或者更新的操作上效能更重要,相對於查詢操作,查詢所帶來的效能損耗更低。平衡效能的確採用Linked List實現更具有優越性。 redis中複合類型的基元素都是String類型。Lists也不例外。Lists類型實質就是一串String元素的序列,redis提供了很多豐富命令,用於操作Lists類型。 1.LPUSH、RPUSH 和 LPOP、RPOP 以及 LRANGE LPUSH從List左邊插入元素,RPUSH從List右邊插入元素。LPOP從List左邊彈出元素並從List中移除該元素,RPOP從List右邊彈出元素並移除。這種操作元素的特點很類似雙向隊列的實現。所以可以用List類型來作為隊列使用,使其用於線程互動。LRANGE是擷取List中的範圍元素。接下來就讓我們看看這些命令如何使用:
127.0.0.1:6379> LPUSH mylist0 name age address phoneNo(integer) 4127.0.0.1:6379> RPUSH mylist1 name age address phoneNo(integer) 4127.0.0.1:6379> LRANGE mylist0 0 -11) "phoneNo"2) "address"3) "age"4) "name"127.0.0.1:6379> LRANGE mylist1 0 -11) "name"2) "age"3) "address"4) "phoneNo"
其中LRANGE中的第二個參數表示要尋找元素的起始位,第三個元素表示結束位(若為負數,表示從List尾部開始計數。例如:-1表示倒數第一位,-2表示倒數第二位),其中mylist0和mylist1元素位置剛好相反。
127.0.0.1:6379> RPOP mylist1"phoneNo"127.0.0.1:6379> RPOP mylist1"address"127.0.0.1:6379> RPOP mylist1"age"127.0.0.1:6379> RPOP mylist1"name"127.0.0.1:6379> RPOP mylist1(nil)
RPOP命令使得mylist1一直從右邊彈出新的元素,並且移除。直到元素為空白。 這裡需要注意:
127.0.0.1:6379> EXISTS mylist1(integer) 0
這時發現mylist1鍵已經不存在。redis提供了非常棒的功能:自動建立或者移除Key。意思是說,不需要預先建立值為空白的Key,在向指定的Key中存入元素的時候如果發現Key不存在就自動建立Key。同理,也不需要刪除元素為空白的鍵,在複雜類型中如果元素為空白,則Key將會被自動刪除。這樣可以保證更有效利用Key空間。
在前面提到List可以用於線程之間的互動通訊,這裡我們簡單的說下List的適用情境: 1.List的PUSH和POP特點決定其可以被用作為隊列使用; 2.List的特點1決定了其具有記憶功能,可以儲存最近的操作,並快速擷取; 3.List的特點1決定了其可被應用於Product/Consumer模式(生產者/消費者模式),生產者放入元素,消費者擷取並消費;
Blocking on List Redis在List的基礎上還提供了Blocking List(阻塞式List),這種List非常類似於Java中的阻塞隊列。採用訊號量機制,和Java中的object的wait和notify、condition的訊號量實現非常相似。正常情況下的List如果擷取元素沒有則返回用戶端為null,但是Blocking on List如果擷取元素為空白,則不返回,此時阻塞用戶端請求,直到有值時才返回,或者可以設定逾時時間,超過設定時間則返回; Redis實現命令BRPOP、BLPOP達到阻塞式List,如果List為空白,則不返回用戶端陷入等待直達有新的元素加入List才返回或者到達指定的逾時時間。
127.0.0.1:6379> 127.0.0.1:6379> 127.0.0.1:6379> BRPOP mylist 10000
如上使用BRPOP命令,則用戶端阻塞等待。第二個參數是逾時時間,如果為0表示一直等待。再開啟一個redis-cli命令視窗,向mylist中添加新的元素:
127.0.0.1:6379> LPUSH mylist lxy(integer) 1127.0.0.1:6379>
則等待的用戶端得到通知,返回新的元素:
127.0.0.1:6379> BRPOP mylist 100001) "mylist"2) "lxy"(218.69s)127.0.0.1:6379>
因為BRPOP可以等待多個List,所以返回時候同時返回List名的元素。第三個參數為已等待時間。
對於Blocking List還有一些規則如下:
A few things to note about BRPOP: Clients are served in an ordered way: the first client that blocked waiting for a list, is served first when an element is pushed by some other client, and so forth. The return value is different compared to RPOP: it is a two-element array since it also includes the name of the key, because BRPOP and BLPOP are able to block waiting for elements from multiple lists. If the timeout is reached, NULL is returned.
Sets類型 Set類型是無序且無重複的String元素的集合。redis也提供了大量對於Sets類型的操作,比如:交集、並集、補集在多個Set之間;測試給定元素是否存在等。 1.SADD sadd命令主要向Set中插入新的元素,如果有則覆蓋,其中可以接多個參數作為插入的元素。
127.0.0.1:6379> SADD myset 0 0 1 2 3 4 5 6 6 6 7 8 8(integer) 9
從上可以看出,雖然有很多重複元素,但是直插入了9個元素。
2.SISMEMBER sismember只要測試指定元素在Set中是否存在,如果存在則返回1,否則返回0
127.0.0.1:6379> SISMEMBER myset 0(integer) 1127.0.0.1:6379> SISMEMBER myset 9(integer) 0127.0.0.1:6379> SISMEMBER myset 7(integer) 1127.0.0.1:6379>
3.SMEBERS smembers擷取Set中的所有元素,並且是無序的
127.0.0.1:6379> SMEMBERS myset1) "0"2) "1"3) "2"4) "3"5) "4"6) "5"7) "6"8) "7"9) "8"127.0.0.1:6379>
4.SINTER sinter用於取多個Set的交集 此外還有很多有關Set的操作命令,但在這裡我們主要以討論資料結構為主,對命令不做詳細講解。在稍後的redis系列中會專門有一節關於常用命令的介紹。
Sorted Set類型 Sorted Set類型是有序的Set類型,有點像Hashes和Set的混合型資料結構。具有Set的唯一無重複特性,且有序的實現是通過額外的浮點值被稱作為score決定,與Hashes的Key有點相似。 Sorted Set的定序,假設有兩個元素a、b 1.如果a.score > b.score,則a > b; 2.如果a.score = b.score,a > b,則a > b; 1.ZADD zadd向Sorted Set中插入元素
127.0.0.1:6379> ZADD mysortset 1 "BACD"(integer) 1127.0.0.1:6379> ZADD mysortset 2 "ABCD<span style="font-family: Arial, Helvetica, sans-serif;">"</span>(integer) 0127.0.0.1:6379> ZADD mysortset 2 "BCDE"(integer) 1
zadd中1,2,2就是這個元素的score,根據score進行排序元素。 2.ZRANGE、ZREVRANGE zrang擷取Sorted Set中的元素,ZREVRANGE擷取Sorted Set中元素並方向輸出。
127.0.0.1:6379> ZRANGE mysortset 0 -11) "BACD"2) "ABCD"3) "BCDE"127.0.0.1:6379>
127.0.0.1:6379> ZREVRANGE mysortset 0 -11) "BCDE"2) "ABCD"3) "BACD"127.0.0.1:6379>
以上後去元素還可以攜帶參數,輸出score
127.0.0.1:6379> ZRANGE mysortset 0 -1 withscores1) "BACD"2) "1"3) "ABCD"4) "2"5) "BCDE"6) "2"127.0.0.1:6379>
Sorted Set不僅僅以上的功能,它還提供了在範圍上的操作: 1.ZRANGBYSCORE zrangbyscore根據score擷取輸出元素, -inf參數表明擷取小於指定score的元素
127.0.0.1:6379> ZRANGEBYSCORE mysortset -inf 4 withscores1) "BACD"2) "1"3) "ABCD"4) "2"5) "BCDE"6) "2"127.0.0.1:6379>
2.ZREMRANGBYSCORE zremrangbyscore擷取指定score範圍內的元素個數
127.0.0.1:6379> ZREMRANGEBYSCORE mysortset 2 6(integer) 3127.0.0.1:6379>
以上只是Sorted Set的簡單命令使用,對於複雜的命令將在後續章節中詳細介紹,這裡只討論資料類型。
Hashes類型
redis中的Hashes類型類似Java中map,key-value索引值對映射型資料結構。redis提供了很多命令用於操作Hashes。
1.HMSET
hmset用於向Hashes中插入元素,插入元素的規則如下:
127.0.0.1:6379> HMSET usr:1000 username lxy birth 1991 verified 1OK127.0.0.1:6379>
2.HMGET、HGET
hmge和HGET都是用於擷取Hashes中的元素,規則如下:
127.0.0.1:6379> HMGET usr:1000 username birth verified1) "lxy"2) "1991"3) "1"127.0.0.1:6379> <span style="font-family: Arial, Helvetica, sans-serif;"></span>
127.0.0.1:6379> HGET usr:1000 username birth(error) ERR wrong number of arguments for 'hget' command127.0.0.1:6379> 127.0.0.1:6379> HGET usr:1000 username"lxy"127.0.0.1:6379>
從以上的使用方式可以看出,HMGET是同時擷取Hashes中的多個Key的值,而HGET一次只能擷取一個。
如發現文章中有錯誤的地方,希望廣大讀者們及時與我溝通,幫我糾正錯誤,謝謝各位的支援!
本篇文章參考:
An introduction to Redis data types and abstractions:http://redis.io/topics/data-types-intro