Redis 不是一個(gè)無(wú)格式 (plain) 的鍵值存儲(chǔ),而是一個(gè)支持各種不同類型值的數(shù)據(jù)結(jié)構(gòu)服務(wù)器。這就是說(shuō),傳統(tǒng)鍵值存儲(chǔ)是關(guān)聯(lián)字符串值到字符串鍵,但是 Redis 的值不僅僅局限于簡(jiǎn)單字符串,還可以持有更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。下面列的是 Redis 支持的所有數(shù)據(jù)結(jié)構(gòu),后面將逐一介紹:
理解這些數(shù)據(jù)結(jié)構(gòu)是如何工作的,以及從命令參考手冊(cè)中選擇什么命令來(lái)解決實(shí)際問(wèn)題,并不總是一件繁瑣的事情,本文檔就是學(xué)習(xí) Redis 數(shù)據(jù)結(jié)構(gòu)及其最常用模式的速成班。
后面的所有例子我們都是使用 redis-cli 工具,這是一個(gè)簡(jiǎn)單而又方便的命令行工具,用于發(fā)送命令給 Redis 服務(wù)器。
Redis 鍵是二進(jìn)制安全的,這意味著你可以使用任何二進(jìn)制序列作為鍵,從像”foo” 這樣的字符串到一個(gè) JPEG 文件的內(nèi)容。空字符串也是合法的鍵。
關(guān)于鍵的其他一些規(guī)則:
Redis 字符串是可以關(guān)聯(lián)給 redis 鍵的最簡(jiǎn)單值類型。字符串是 Memcached 的唯一數(shù)據(jù)類型,所以新手使用起來(lái)也是很自然的。
由于 Redis 的鍵也是字符串,當(dāng)我們使用字符串作為值的時(shí)候,我們是將一個(gè)字符串映射給另一個(gè)字符串。字符串?dāng)?shù)據(jù)類型適用于很多場(chǎng)景,例如,緩存 HTML 片段或者頁(yè)面。
讓我們用 redis-cli 來(lái)玩玩字符串類型 (接下來(lái)的例子都是使用 redis-cli)。
> set mykey somevalue
OK
> get mykey
"somevalue"
你可以看到,我們使用 SET 和 GET 命令設(shè)置和檢索字符串值。注意,如果鍵已經(jīng)存在,SET 會(huì)替換掉該鍵已經(jīng)存在的值,哪怕這個(gè)鍵關(guān)聯(lián)的是一個(gè)非字符串類型的值。SET 執(zhí)行的是賦值操作。
值可以是任何類型的字符串 (包括二進(jìn)制數(shù)據(jù)),例如,你可以存儲(chǔ)一個(gè) JPEG 圖像。值不能大于 512MB。
SET 命令還有一些以額外的參數(shù)形式提供有意思的選項(xiàng)。例如,如果我要求如果鍵存在 (或剛好相反) 則執(zhí)行失敗,也就是說(shuō)健存在才成功:
> set mykey newval nx
(nil)
> set mykey newval xx
OK
盡管字符串是 Redis 最基本的值類型,你仍可以執(zhí)行很多有趣的操作。例如,原子性增長(zhǎng):
> set counter 100
OK
> incr counter
(integer) 101
> incr counter
(integer) 102
> incrby counter 50
(integer) 152
INCR 命令將字符串值解析為整數(shù),并增加一,最后賦值后作為新值。還有一些類似的命令 INCRBY,DECR 和 DECRBY。它們以略微不同的方式執(zhí)行,但其內(nèi)部都是一樣的命令。
為什么說(shuō) INCR 命令是原子的?因?yàn)榧词苟鄠€(gè) 客戶端對(duì)同一個(gè)鍵發(fā)送 INCR 命令也不會(huì)造成競(jìng)爭(zhēng)條件 (race condition)。例如,一定不會(huì)發(fā)生客戶端 1 和客戶端 2 同時(shí)讀到”10”,都增加到 11,然后設(shè)置新值為 11。最后的結(jié)果將會(huì)一直是 12,讀 - 增加 - 寫操作在執(zhí)行時(shí),其他客戶端此時(shí)不會(huì)執(zhí)行相關(guān)命令。
有許多操作字符串的命令。例如,GETSET 命令給鍵設(shè)置一個(gè)新值,同時(shí)返回舊值。你可以使用這個(gè)命令,例如,如果你有一個(gè)系統(tǒng),每當(dāng)收到一個(gè)訪問(wèn)請(qǐng)求就使用 INRC 來(lái)增加一個(gè)鍵。你想每隔一個(gè)小時(shí)收集一次這個(gè)信息,而不想漏掉任何一個(gè)增長(zhǎng)。你可以使用 GETSET,將新值賦值為 0,人后讀取其舊值。
在一個(gè)命令中一次設(shè)置或者檢索多個(gè)鍵有利于減少延遲。為此有了 MSET 和 MGET 命令:
> mset a 10 b 20 c 30
OK
> mget a b c
1) "10"
2) "20"
3) "30"
當(dāng)使用 MSET 時(shí),Redis 返回一個(gè)值數(shù)組。
有一些命令并不定義在特定的類型上,但是對(duì)鍵空間的交互很有用,因此他們能作用在任意鍵上。
例如,EXISTS 命令返回 1 或者 0,來(lái)表示鍵在數(shù)據(jù)庫(kù)中是否存在。另外,DEL 命令刪除鍵及其關(guān)聯(lián)的值,無(wú)論值是什么。
> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0
從上面的例子中我們還可以看到,DEL 命令本身也會(huì)返回 1 或者 0,無(wú)論鍵是(存在)否(不存在)刪除。
有許多鍵空間相關(guān)的命令,但是上面兩個(gè)命令與 TYPE 命令關(guān)系緊密,TYPE 命令返回某個(gè)鍵的值的類型。
> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none
在我們繼續(xù)更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)之前,我們先拋出一個(gè)與類型無(wú)關(guān)的特性, 稱為 Redis 過(guò)期 。你可以給鍵設(shè)置超時(shí),也就是一個(gè)有限的生存時(shí)間。當(dāng)生存時(shí)間到了,鍵就會(huì)自動(dòng)被銷毀,就像用戶調(diào)用 DEL 命令一樣。
快速過(guò)一下 Redis 過(guò)期的信息:
設(shè)置過(guò)期非常簡(jiǎn)單:
> set key some-value
OK
> expire key 5
(integer) 1
> get key (immediately)
"some-value"
> get key (after some time)
(nil)
鍵在兩次 GET 調(diào)用期間消失了,因?yàn)榈诙握{(diào)用推遲了超過(guò) 5 秒。在上面的例子中,我們使用 EXPIRE 命令設(shè)置過(guò)期 (也可以為一個(gè)已經(jīng)設(shè)置過(guò)期時(shí)間的鍵設(shè)置不同的過(guò)期時(shí)間,就像 PERSIST 命令可以刪除過(guò)期時(shí)間使鍵永遠(yuǎn)存在)。當(dāng)然我們也可以使用其他 Redis 命令來(lái)創(chuàng)建帶過(guò)期時(shí)間的鍵。例如使用 SET 選項(xiàng):
> set key 100 ex 10
OK
> ttl key
(integer) 9
上面的例子中設(shè)置 10 秒過(guò)期的鍵,值為字符串 100。然后使用 TTL 命令檢查鍵的生存剩余時(shí)間。
為了使用毫秒來(lái)設(shè)置和檢查過(guò)期,請(qǐng)查看 PEXPIRE 和 PTTL 命令,以及 SET 命令的全部選項(xiàng)。