Redis數據類型

Redis數據類型

Redis支持5種數據類型。
字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets)

字符串(Strings命令組)

Redis中的字符串是一個字節序列。Redis中的字符串是二進制安全的,這意味着它們的長度不由任何特殊的終止字符決定。這意味着可以用任何二進制序列作爲key值,從形如”foo”的簡單字符串到一個JPEG文件的內容都可以。因此,可以在一個字符串中存儲高達512兆字節的任何內容。
示例

> set mykey somevalue
OK
> get mykey
"somevalue"

注 - Redis命令不區分大小寫,如SET,Set和set都是同一個命令。字符串值的最大長度爲 512MB。

SET 命令有些有趣的操作,例如,當key存在時SET會失敗,或相反的,當key不存在時它只會成功。

set mykey newval nx
(nil)
set mykey newval xx
OK

原子遞增incr:

> set counter 100
OK
> incr counter
(integer) 101
> incr counter
(integer) 102
> incrby counter 50
(integer) 152

INCR 命令將字符串值解析成整型,將其加一,最後將結果保存爲新的字符串值,類似的命令有INCRBY, DECR 和 DECRBY。實際上他們在內部就是同一個命令,只是看上去有點兒不同。
INCR是原子操作意味着什麼呢?就是說即使多個客戶端對同一個key發出INCR命令,也決不會導致競爭的情況。例如如下情況永遠不可能發生:『客戶端1和客戶端2同時讀出“10”,他們倆都對其加到11,然後將新值設置爲11』。最終的值一定是12,read-increment-set操作完成時,其他客戶端不會在同一時間執行任何命令。(保證原子性)

GETSET:爲key設置新值並且返回原值(重置字符串)。這有什麼用處呢?例如:你的系統每當有新用戶訪問時就用INCR命令操作一個Redis key。你希望每小時對這個信息收集一次。你就可以GETSET這個key並給其賦值0並讀取原值。

MSET和MGET:一次存儲或獲取多個key對應的值

> mset a 10 b 20 c 30
OK
> mget a b c
1) "10"
2) "20"
3) "30"

MGET 命令返回由值組成的數組。

修改或查詢鍵空間
有些指令不是針對任何具體的類型定義的,而是用於和整個鍵空間交互的。因此,它們可被用於任何類型的鍵。
使用EXISTS命令返回1或0標識給定key的值是否存在,使用DEL命令可以刪除key對應的值,DEL命令返回1或0標識值是被刪除(值存在)或者沒被刪除(key對應的值不存在)。

> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0

TYPE命令可以返回key對應的值的存儲類型:

> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none

Redis超時:數據在限定時間內存活
在介紹複雜類型前我們先介紹一個與值類型無關的Redis特性:超時。你可以對key設置一個超時時間,當這個時間到達後會被刪除。精度可以使用毫秒或秒。

> set key some-value
OK
> expire key 5
(integer) 1
> get key (immediately)
"some-value"
> get key (after some time)
(nil)

上面的例子使用了EXPIRE來設置超時時間(也可以再次調用這個命令來改變超時時間,使用PERSIST命令去除超時時間 )。我們也可以在創建值的時候設置超時時間:

> set key 100 ex 10
OK
> ttl key
(integer) 9

TTL命令用來查看key對應的值剩餘存活時間。

列表(Lists命令組)
Redis lists基於Linked Lists實現。這意味着即使在一個list中有數百萬個元素,在頭部或尾部添加一個元素的操作,其時間複雜度也是常數級別的。用LPUSH 命令在十個元素的list頭部添加新元素,和在千萬元素list頭部添加新元素的速度相同。
那麼,壞消息是什麼?在數組實現的list中利用索引訪問元素的速度極快,而同樣的操作在linked list實現的list上沒有那麼快,無法隨機訪問,想要快速訪問使用Sorted Sets。
Redis Lists用linked list實現的原因是:對於數據庫系統來說,至關重要的特性是:能非常快的在很大的列表上添加元素。另一個重要因素是,正如你將要看到的:Redis lists能在常數時間取得常數長度。

LPUSH :向list的左邊(頭部)添加一個新元素
RPUSH:向list的右邊(尾部)添加一個新元素
LRANGE :從list中取出一定範圍的元素
LRANGE 帶有兩個索引,一定範圍的第一個和最後一個元素。這兩個索引都可以爲負來告知Redis從尾部開始計數,因此-1表示最後一個元素,-2表示list中的倒數第二個元素,以此類推。
Lpop&Rpop:list中刪除元素並同時返回刪除的值。可以在左邊或右邊操作。

List的常用案例
正如你可以從上面的例子中猜到的,list可被用來實現聊天系統。還可以作爲不同進程間傳遞消息的隊列。關鍵是,你可以每次都以原先添加的順序訪問數據。這不需要任何SQL ORDER BY 操作,將會非常快,也會很容易擴展到百萬級別元素的規模。
例如在評級系統中,比如社會化新聞網站 reddit.com,你可以把每個新提交的鏈接添加到一個list,用LRANGE可簡單的對結果分頁。
在博客引擎實現中,你可爲每篇日誌設置一個list,在該list中推入博客評論,等等。
Capped lists
LTRIM:把list從左邊截取指定長度。

> rpush mylist 1 2 3 4 5
(integer) 5
> ltrim mylist 0 2
OK
> lrange mylist 0 -1
1) "1"
2) "2"
3) "3"

List上的阻塞操作
可以使用Redis來實現生產者和消費者模型,如使用LPUSH和RPOP來實現該功能。但會遇到這種情景:list是空,這時候消費者就需要輪詢來獲取數據,這樣就會增加redis的訪問壓力、增加消費端的cpu時間,而很多訪問都是無用的。爲此redis提供了阻塞式訪問 BRPOP 和 BLPOP 命令。 消費者可以在獲取數據時指定如果數據不存在阻塞的時間,如果在時限內獲得數據則立即返回,如果超時還沒有數據則返回null, 0表示一直阻塞。
同時redis還會爲所有阻塞的消費者以先後順序排隊。
如需瞭解詳細信息請查看 RPOPLPUSH 和 BRPOPLPUSH。

key 的自動創建和刪除
目前爲止,在我們的例子中,我們沒有在推入元素之前創建空的 list,或者在 list 沒有元素時刪除它。在 list 爲空時刪除 key,並在用戶試圖添加元素(比如通過 LPUSH)而鍵不存在時創建空 list,是 Redis 的職責。
這不光適用於 lists,還適用於所有包括多個元素的 Redis 數據類型 – Sets, Sorted Sets 和 Hashes。
基本上,我們可以用三條規則來概括它的行爲:
1、當我們向一個聚合數據類型中添加元素時,如果目標鍵不存在,就在添加元素前創建空的聚合數據類型。
2、當我們從聚合數據類型中移除元素時,如果值仍然是空的,鍵自動被銷燬。
3、對一個空的 key 調用一個只讀的命令,比如 LLEN (返回 list 的長度),或者一個刪除元素的命令,將總是產生同樣的結果。該結果和對一個空的聚合類型做同個操作的結果是一樣的。
規則 1 示例:

> del mylist
(integer) 1
> lpush mylist 1 2 3
(integer) 3

但是,我們不能對存在但類型錯誤的 key 做操作: > set foo bar OK > lpush foo 1 2 3 (error) WRONGTYPE Operation against a key holding the wrong kind of value > type foo string
規則 2 示例:

> lpush mylist 1 2 3
(integer) 3
> exists mylist
(integer) 1
> lpop mylist
"3"
> lpop mylist
"2"
> lpop mylist
"1"
> exists mylist
(integer) 0

所有的元素被彈出之後, key 不復存在。
規則 3 示例:

> del mylist
(integer) 0
> llen mylist
(integer) 0
> lpop mylist
(nil)

> rpush mylist A
(integer) 1
> rpush mylist B
(integer) 2
> lpush mylist first
(integer) 3
> lrange mylist 0 -1
1) "first"
2) "A"
3) "B"
> rpush mylist a b c
(integer) 3
> rpop mylist
"c"
> rpop mylist
"b"
> rpop mylist
"a"

注意:列表的最大長度爲2^32 - 1個元素(4294967295,每個列表可容納超過40億個元素)。

散列/哈希(Hashes命令組)
Redis散列/哈希是鍵值對的集合。Redis散列/哈希是字符串字段和字符串值之間的映射。因此,它們用於表示對象。
示例

> HMSET ukey username "zysung" password "passswd123" points 200

在上述示例中,散列/哈希數據類型用於存儲包含用戶的基本信息的用戶對象。這裏HMSET,HGETALL是Redis的命令,而ukey是鍵的名稱。
每個散列/哈希可以存儲多達2^32 - 1個健-值對(超過40億個)。

完整Hashes命令:
HDEL key field [field …] 刪除一個或多個Hash的field
HEXISTS key field 判斷field是否存在於hash中,返回0,1
HGET key field 獲取hash中field的值
HGETALL key 從hash中讀取全部的域和值
HINCRBY key field increment 將hash中指定域的值增加給定的數字
HINCRBYFLOAT key field increment 將hash中指定域的值增加給定的浮點數
HKEYS key 獲取hash的所有字段
HLEN key 獲取hash裏所有字段的數量
HMGET key field [field …] 獲取hash裏面指定字段的值
HMSET key field value [field value …] 設置hash字段值
HSET key field value 設置hash裏面一個字段的值
HSETNX key field value 設置hash的一個字段,只有當這個字段不存在時有效
HSTRLEN key field獲取hash裏面指定field的長度
HVALS key獲得hash的所有值
HSCAN key cursor [MATCH pattern] [COUNT count]迭代hash裏面的元素
ex:

> hkeys ukey
1) "username"
2) "password"
> hmget ukey username
1) "zysung"

值得注意的是,小的 hash 被用特殊方式編碼,非常節約內存。

集合(Sets命令組)
Redis Set 是 String 的無序排列。SADD 指令把新的元素添加到 set 中。對 set 也可做一些其他的操作,比如測試一個給定的元素是否存在,對不同 set 取並交差,等等。

> sadd myset 1 2 3
(integer) 3
> smembers myset
1. 3
2. 1
3. 2

集合具有唯一屬性,一個值不能被添加兩次,與列表不同

> sadd mySet 1 2 2
(integer) 2

sismember: 檢測成員是否存在集合中的指令

> sismember myset 30
(integer) 0

Sets 適合用於表示對象間的關係。
例如,我們可以輕易使用 set 來表示標記。
一個簡單的建模方式是,對每一個希望標記的對象使用 set。這個 set 包含和對象相關聯的標籤的 ID。
假設我們想要給新聞打上標籤。 假設新聞 ID 1000 被打上了 1,2,5 和 77 四個標籤,我們可以使用一個 set 把 tag ID 和新聞條目關聯起來:

> sadd news:1000:tags 1 2 5 77
(integer) 4

但是,有時候我可能也會需要相反的關係:所有被打上相同標籤的新聞列表:

> sadd tag:1:news 1000
(integer) 1
> sadd tag:2:news 1000
(integer) 1
> sadd tag:5:news 1000
(integer) 1
> sadd tag:77:news 1000
(integer) 1

獲取一個對象的所有 tag 是很方便的:

> smembers news:1000:tags
1. 5
2. 1
3. 77
4. 2

注意:在這個例子中,我們假設你有另一個數據結構,比如一個 Redis hash,把標籤 ID 對應到標籤名稱。

SINTER :獲取不同 set 的交集。

127.0.0.1:6379> sadd myset1 zysung dodoci
(integer) 2
127.0.0.1:6379> sadd myset2 song dodoci
(integer) 2
127.0.0.1:6379> sinter myset1 myset2
1) "dodoci"

還可以取並集,差集,獲取隨機元素

獲取一個元素的命令是 SPOP,它很適合對特定問題建模。比如,要實現一個基於 web 的撲克遊戲,你可能需要用 set 來表示一副牌。假設我們用一個字符的前綴來表示不同花色:

>  sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK
   D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3
   H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6
   S7 S8 S9 S10 SJ SQ SK
(integer) 52

現在,我們想要給每個玩家 5 張牌。SPOP 命令刪除一個隨機元素,把它返回給客戶端,因此它是完全合適的操作。
但是,如果我們對我們的牌直接調用它,在下一盤我們就需要重新充滿這副牌。開始,我們可以複製 deck 鍵中的內容,並放入 game:1:deck 鍵中。

sunionstore命令:取並集放入另一集合中,sunion只取並集

> sunionstore myset2 myset1 myset2
(integer) 3

scard:計算set中key的個數
spop:隨機從集合中刪除一個數並返回

可排序集合(Sorted Sets命令組)
Redis可排序集合類似於Redis集合與散列之間,是不重複的字符集合。 不同之處在於,排序集合的每個成員都與一個分數score相關聯,這個分數用於按最小分數到最大分數來排序的排序集合(像hash,每個元素都有一個值映射)。雖然成員是唯一的(不可重複key),但分數值可以重複。
SortedSets的排序規則:先按分數,若分數相同按字典順序

127.0.0.1:6379> zadd users 19950419 song
(integer) 1
127.0.0.1:6379> zadd users 19951119 truesong
(integer) 1
127.0.0.1:6379> zrange users 0 -1
1) "song"
2) "truesong"
127.0.0.1:6379> zrevrange users 0 -1
1) "truesong"
2) "song"
127.0.0.1:6379> zrange users 0 -1 withscores
1) "song"
2) "19950419"
3) "truesong"
4) "19951119"
127.0.0.1:6379> zrange users 0 -1 withscores
1) "song"
2) "19950419"
3) "truesong"
4) "19951119"

asked Redis to return all the elements with a score between negative infinity and 19951000

127.0.0.1:6379> zrangebyscore users -inf 19951000
1) "song"
127.0.0.1:6379> zrangebyscore users  19951000 inf
1) "truesong"
127.0.0.1:6379> zrangebyscore users 19951000 19951231
1) "truesong"

分數相同的,按字典順序排序
也可直接要求按字典順序
Using ZRANGEBYLEX we can ask for lexicographical ranges:

> zrangebylex hackers [B [P
1) "Claude Shannon"
2) "Hedy Lamarr"
3) "Linus Torvalds"

參見:redis.cn

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