1. 程式人生 > >redis命令參考手冊完整版

redis命令參考手冊完整版

Redis 命令參考


Key(鍵)
DEL
格式:DEL key [key ...]
刪除給定的一個或多個 key 。
不存在的 key 會被忽略。
可用版本:
>= 1.0.0
時間複雜度:
O(N), N 為被刪除的 key 的數量。
刪除單個字串型別的 key ,時間複雜度為O(1)。
刪除單個列表、集合、有序集合或雜湊表型別的 key ,時間複雜度為O(M), M 為以
上資料結構內的元素數量。
返回值:
被刪除 key 的數量。
示例程式碼:
# 刪除單個 key
redis> SET name huangz
OK
redis> DEL name
(integer) 1
# 刪除一個不存在的 key
redis> EXISTS phone
(integer) 0
redis> DEL phone # 失敗,沒有 key 被刪除
(integer) 0
# 同時刪除多個 key
redis> SET name "redis"
OK
redis> SET type "key-value store"
OK
redis> SET website "redis.com"
OK
redis> DEL name type website
(integer) 3
KEYS
格式:keys pattern
查詢所有符合給定模式 pattern 的 key 。
KEYS * 匹配資料庫中所有 key 。
KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
KEYS h*llo 匹配 hllo 和 heeeeello 等。
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。
特殊符號用 \ 隔開
警告:KEYS 的速度非常快,但在一個大的資料庫中使用它仍然可能造成效能問題,如
果你需要從一個數據集中查詢特定的 key ,你最好還是用 Redis 的集合結構(set)來代替。
可用版本:
>= 1.0.0
時間複雜度:
O(N), N 為資料庫中 key 的數量。
返回值:
符合給定模式的 key 列表。
示例程式碼:
redis> MSET one 1 two 2 three 3 four 4 # 一次設定 4 個 key
OK
redis> KEYS *o*
1) "four"
2) "two"
3) "one"
redis> KEYS t??
1) "two"
redis> KEYS t[w]*
1) "two"
redis> KEYS * # 匹配資料庫內所有 key
1) "four"
2) "three"
3) "two"
4) "one"
RANDOMKEY
格式:randomkey
從當前資料庫中隨機返回(不刪除)一個 key 。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
當資料庫不為空時,返回一個 key 。
當資料庫為空時,返回 nil 。
示例程式碼:
# 資料庫不為空
redis> MSET fruit "apple" drink "beer" food "cookies" # 設定多個 key
OK
redis> RANDOMKEY
"fruit"
redis> RANDOMKEY
"food"
redis> KEYS * # 檢視資料庫內所有key,證明 RANDOMKEY 並不刪除 key
1) "food"
2) "drink"
3) "fruit"
# 資料庫為空
redis> FLUSHDB # 刪除當前資料庫所有 key
OK
redis> RANDOMKEY
(nil)
TTL
格式:ttl key
以秒為單位,返回給定 key 的剩餘生存時間(TTL, time to live)。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
當 key 不存在時,返回 -2 。
當 key 存在但沒有設定剩餘生存時間時,返回 -1 。
否則,以秒為單位,返回 key 的剩餘生存時間。
注:在 Redis 2.8 以前,當 key 不存在,或者 key 沒有設定剩餘生存時間時,命令
都返回 -1 。
示例程式碼:
# 不存在的 key
redis> FLUSHDB
OK
redis> TTL key
(integer) -2
# key 存在,但沒有設定剩餘生存時間
redis> SET key value
OK
redis> TTL key
(integer) -1
# 有剩餘生存時間的 key
redis> EXPIRE key 10086
(integer) 1
redis> TTL key
(integer) 10084
PTTL
格式:pttl key
這個命令類似於 TTL 命令,但它以毫秒為單位返回 key 的剩餘生存時間,而不是像
TTL 命令那樣,以秒為單位。
可用版本:
>= 2.6.0
複雜度:
O(1)
返回值:
當 key 不存在時,返回 -2 。
當 key 存在但沒有設定剩餘生存時間時,返回 -1 。
否則,以毫秒為單位,返回 key 的剩餘生存時間。
注:在 Redis 2.8 以前,當 key 不存在,或者 key 沒有設定剩餘生存時間時,命令
都返回 -1 。
示例程式碼:
# 不存在的 key
redis> FLUSHDB
OK
redis> PTTL key
(integer) -2
# key 存在,但沒有設定剩餘生存時間
redis> SET key value
OK
redis> PTTL key
(integer) -1
# 有剩餘生存時間的 key
redis> PEXPIRE key 10086
(integer) 1
redis> PTTL key
(integer) 6179
EXISTS
格式:exists key
檢查給定 key 是否存在。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
若 key 存在,返回 1 ,否則返回 0 。
示例程式碼:
redis> SET db "redis"
OK
redis> EXISTS db
(integer) 1
redis> DEL db
(integer) 1
redis> EXISTS db
(integer) 0
MOVE
格式:move key db
將當前資料庫的 key 移動到給定的資料庫 db 當中。
如果當前資料庫(源資料庫)和給定資料庫(目標資料庫)有相同名字的給定 key ,或者
key 不存在於當前資料庫,那麼 MOVE 沒有任何效果。
因此,也可以利用這一特性,將 MOVE 當作鎖(locking)原語(primitive)。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
移動成功返回 1 ,失敗則返回 0 。
示例程式碼:
# key 存在於當前資料庫
redis> SELECT 0 #redis 預設使用資料庫 0,為了清晰起見,這裡再顯式指定一次。
OK
redis> SET song "secret base - Zone"
OK
redis> MOVE song 1 # 將 song 移動到資料庫 1
(integer) 1
redis> EXISTS song # song 已經被移走
(integer) 0
redis> SELECT 1 # 使用資料庫 1
OK
redis:1> EXISTS song # 證實 song 被移到了資料庫 1 (注意命
令提示符變成了"redis:1",表明正在使用資料庫 1)
(integer) 1
# 當 key 不存在的時候
redis:1> EXISTS fake_key
(integer) 0
redis:1> MOVE fake_key 0 # 試圖從資料庫 1 移動一個不存在的 key 到資料庫
0,失敗
(integer) 0
redis:1> select 0 # 使用資料庫0
OK
redis> EXISTS fake_key # 證實 fake_key 不存在
(integer) 0
# 當源資料庫和目標資料庫有相同的 key 時
redis> SELECT 0 # 使用資料庫0
OK
redis> SET favorite_fruit "banana"
OK
redis> SELECT 1 # 使用資料庫1
OK
redis:1> SET favorite_fruit "apple"
OK
redis:1> SELECT 0 # 使用資料庫0,並試圖將 favorite_fruit 移動到資料庫 1
OK
redis> MOVE favorite_fruit 1 # 因為兩個資料庫有相同的 key,MOVE 失敗
(integer) 0
redis> GET favorite_fruit # 資料庫 0 的 favorite_fruit 沒變
"banana"
redis> SELECT 1
OK
redis:1> GET favorite_fruit # 資料庫 1 的 favorite_fruit 也是
"apple"
RENAME
格式:rename key newkey
將 key 改名為 newkey 。
當 key 和 newkey 相同,或者 key 不存在時,返回一個錯誤。
當 newkey 已經存在時, RENAME 命令將覆蓋舊值。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
改名成功時提示 OK ,失敗時候返回一個錯誤。
示例程式碼:
# key 存在且 newkey 不存
redis> SET message "hello world"
OK
redis> RENAME message greeting
OK
redis> EXISTS message # message 不復存在
(integer) 0
redis> EXISTS greeting # greeting 取而代之
(integer) 1
# 當 key 不存在時,返回錯誤
redis> RENAME fake_key never_exists
(error) ERR no such key
# newkey 已存在時, RENAME 會覆蓋舊 newkey
redis> SET pc "lenovo"
OK
redis> SET personal_computer "dell"
OK
redis> RENAME pc personal_computer
OK
redis> GET pc
(nil)
redis:1> GET personal_computer # 原來的值 dell 被覆蓋了
"lenovo"
RENAMENX
格式:renamenx key newkey
當且僅當 newkey 不存在時,將 key 改名為 newkey 。
當 key 不存在時,返回一個錯誤。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
修改成功時,返回 1 。
如果 newkey 已經存在,返回 0 。
示例程式碼:
# newkey 不存在,改名成功
redis> SET player "MPlyaer"
OK
redis> EXISTS best_player
(integer) 0
redis> RENAMENX player best_player
(integer) 1
# newkey 存在時,失敗
redis> SET animal "bear"
OK
redis> SET favorite_animal "butterfly"
OK
redis> RENAMENX animal favorite_animal
(integer) 0
redis> get animal
"bear"
redis> get favorite_animal
"butterfly"
TYPE
格式:type key
返回 key 所儲存的值的型別。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
none (key 不存在)
string (字串)
list (列表)
set (集合)
zset (有序集)
hash (雜湊表)
示例程式碼:
# 字串
redis> SET weather "sunny"
OK
redis> TYPE weather
string
# 列表
redis> LPUSH book_list "programming in scala"
(integer) 1
redis> TYPE book_list
list
# 集合
redis> SADD pat "dog"
(integer) 1
redis> TYPE pat
set
EXPIRE
格式:expire key seconds
為給定 key 設定生存時間,當 key 過期時(生存時間為 0 ),它會被自動刪除。
在 Redis 中,帶有生存時間的 key 被稱為『可揮發』(volatile)的。
生存時間可以通過使用 DEL 命令來刪除整個 key 來移除,或者被 SET 和 GETSET 命
令覆寫(overwrite),這意味著,如果一個命令只是修改(alter)一個帶生存時間的 key 的
值而不是用一個新的 key 值來代替(replace)它的話,那麼生存時間不會被改變。
比如說,對一個 key 執行 INCR 命令,對一個列表進行 LPUSH 命令,或者對一個雜湊
表執行 HSET 命令,這類操作都不會修改 key 本身的生存時間。
另一方面,如果使用 RENAME 對一個 key 進行改名,那麼改名後的 key 的生存時間和
改名前一樣。
RENAME 命令的另一種可能是,嘗試將一個帶生存時間的 key 改名成另一個帶生存時間
的 another_key ,這時舊的 another_key (以及它的生存時間)會被刪除,然後舊的 key 會
改名為 another_key ,因此,新的 another_key 的生存時間也和原本的 key 一樣。
使用 PERSIST 命令可以在不刪除 key 的情況下,移除 key 的生存時間,讓 key 重新
成為一個『持久化』(persistent) key 。
更新生存時間
可以對一個已經帶有生存時間的 key 執行 EXPIRE 命令,新指定的生存時間會取代舊
的生存時間。
過期時間的精確度
在 Redis 2.4 版本中,過期時間的延遲在 1 秒鐘之內 —— 也即是,就算 key 已經
過期,但它還是可能在過期之後一秒鐘之內被訪問到,而在新的 Redis 2.6 版本中,延遲
被降低到 1 毫秒之內。
Redis 2.1.3 之前的不同之處
在 Redis 2.1.3 之前的版本中,修改一個帶有生存時間的 key 會導致整個 key 被刪
除,這一行為是受當時複製(replication)層的限制而作出的,現在這一限制已經被修復。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
設定成功返回 1 。
當 key 不存在或者不能為 key 設定生存時間時(比如在低於 2.1.3 版本的 Redis 中
你嘗試更新 key 的生存時間),返回 0 。
示例程式碼:
redis> SET cache_page "www.google.com"
OK
redis> EXPIRE cache_page 30 # 設定過期時間為 30 秒
(integer) 1
redis> TTL cache_page # 檢視剩餘生存時間
(integer) 23
redis> EXPIRE cache_page 30000 # 更新過期時間
(integer) 1
redis> TTL cache_page
(integer) 29996
模式:導航會話
假設你有一項 web 服務,打算根據使用者最近訪問的 N 個頁面來進行物品推薦,並且假
設使用者停止閱覽超過 60 秒,那麼就清空閱覽記錄(為了減少物品推薦的計算量,並且保持
推薦物品的新鮮度)。
這些最近訪問的頁面記錄,我們稱之為『導航會話』(Navigation session),可以用 INCR
和 RPUSH 命令在 Redis 中實現它:每當使用者閱覽一個網頁的時候,執行以下程式碼:
MULTI
RPUSH pagewviews.user:<userid> http://.....
EXPIRE pagewviews.user:<userid> 60
EXEC
如果使用者停止閱覽超過 60 秒,那麼它的導航會話就會被清空,當用戶重新開始閱覽的
時候,系統又會重新記錄導航會話,繼續進行物品推薦。
PEXPIRE
格式:pexpire key milliseconds
這個命令和 EXPIRE 命令的作用類似,但是它以毫秒為單位設定 key 的生存時間,而
不像 EXPIRE 命令那樣,以秒為單位。
可用版本:
>= 2.6.0
時間複雜度:
O(1)
返回值:
設定成功,返回 1
key 不存在或設定失敗,返回 0
示例程式碼:
redis> SET mykey "Hello"
OK
redis> PEXPIRE mykey 1500
(integer) 1
redis> TTL mykey # TTL 的返回值以秒為單位
(integer) 2
redis> PTTL mykey # PTTL 可以給出準確的毫秒數
(integer) 1499
EXPIREAT
格式:expireat key timestamp
EXPIREAT 的作用和 EXPIRE 類似,都用於為 key 設定生存時間。
不同在於 EXPIREAT 命令接受的時間引數是 UNIX 時間戳(unix timestamp)。
可用版本:
>= 1.2.0
時間複雜度:
O(1)
返回值:
如果生存時間設定成功,返回 1 。
當 key 不存在或沒辦法設定生存時間,返回 0 。
示例程式碼:
redis> SET cache www.google.com
OK
redis> EXPIREAT cache 1355292000 # 這個 key 將在 2012.12.12 過期
(integer) 1
redis> TTL cache
(integer) 45081860
PEXPIREAT
格式:pexpireat key milliseconds
這個命令和 EXPIREAT 命令類似,但它以毫秒為單位設定 key 的過期 unix 時間戳,
而不是像 EXPIREAT 那樣,以秒為單位。
可用版本:
>= 2.6.0
時間複雜度:
O(1)
返回值:
如果生存時間設定成功,返回 1 。
當 key 不存在或沒辦法設定生存時間時,返回 0 。
示例程式碼:
redis> SET mykey "Hello"
OK
redis> PEXPIREAT mykey 1555555555005
(integer) 1
redis> TTL mykey # TTL 返回秒
(integer) 223157079
redis> PTTL mykey # PTTL 返回毫秒
(integer) 223157079318
PERSIST
格式:persist key
移除給定 key 的生存時間,將這個 key 從『可揮發』的(帶生存時間 key )轉換成『持
久化』的(一個不帶生存時間、永不過期的 key )。
可用版本:
>= 2.2.0
時間複雜度:
O(1)
返回值:
當生存時間移除成功時,返回 1 .
如果 key 不存在或 key 沒有設定生存時間,返回 0 。
示例程式碼:
redis> SET mykey "Hello"
OK
redis> EXPIRE mykey 10 # 為 key 設定生存時間
(integer) 1
redis> TTL mykey
(integer) 10
redis> PERSIST mykey # 移除 key 的生存時間
(integer) 1
redis> TTL mykey
(integer) -1
SORT
格式:sort key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]]
[ASC | DESC] [ALPHA] [STORE destination]
返回或儲存給定列表、集合、有序集合 key 中經過排序的元素。
排序預設以數字作為物件,值被解釋為雙精度浮點數,然後進行比較。
一般SORT 用法
最簡單的 SORT 使用方法是 SORT key 。
假設 today_cost 是一個儲存數字的列表, SORT 命令預設會返回該列表值的遞增(從
小到大)排序結果。
示例程式碼:
# 將資料一一加入到列表中
redis> LPUSH today_cost 30
(integer) 1
redis> LPUSH today_cost 1.5
(integer) 2
redis> LPUSH today_cost 10
(integer) 3
redis> LPUSH today_cost 8
(integer) 4
# 排序
redis> SORT today_cost
1) "1.5"
2) "8"
3) "10"
4) "30"
當資料集中儲存的是字串值時,你可以用 ALPHA 修飾符(modifier)進行排序。
# 將資料一一加入到列表中
redis> LPUSH website "www.reddit.com"
(integer) 1
redis> LPUSH website "www.slashdot.com"
(integer) 2
redis> LPUSH website "www.infoq.com"
(integer) 3
# 預設排序
redis> SORT website
1) "www.infoq.com"
2) "www.slashdot.com"
3) "www.reddit.com"
# 按字元排序
redis> SORT website ALPHA
1) "www.infoq.com"
2) "www.reddit.com"
3) "www.slashdot.com"
如果你正確設定了 !LC_COLLATE 環境變數的話,Redis 能識別 UTF-8 編碼。
排序之後返回的元素數量可以通過 LIMIT 修飾符進行限制。
LIMIT 修飾符接受兩個引數: offset 和 count 。
offset 指定要跳過的元素數量, count 指定跳過 offset 個指定的元素之後,要返回
多少個物件。
以下例子返回排序結果的前 5 個物件( offset 為 0 表示沒有元素被跳過)。
# 將資料一一加入到列表中
redis> LPUSH rank 30
(integer) 1
redis> LPUSH rank 56
(integer) 2
redis> LPUSH rank 42
(integer) 3
redis> LPUSH rank 22
(integer) 4
redis> LPUSH rank 0
(integer) 5
redis> LPUSH rank 11
(integer) 6
redis> LPUSH rank 32
(integer) 7
redis> LPUSH rank 67
(integer) 8
redis> LPUSH rank 50
(integer) 9
redis> LPUSH rank 44
(integer) 10
redis> LPUSH rank 55
(integer) 11
# 排序
redis> SORT rank LIMIT 0 5 # 返回排名前五的元素
1) "0"
2) "11"
3) "22"
4) "30"
5) "32"
修飾符可以組合使用。以下例子返回降序(從大到小)的前 5 個物件。
redis> SORT rank LIMIT 0 5 DESC
1) "78"
2) "67"
3) "56"
4) "55"
5) "50"
使用外部 key 進行排序
有時候你會希望使用外部的 key 作為權重來比較元素,代替預設的對比方法。
假設現在有使用者(user)資料如下:
id name level
1 admin 9999
2 huangz 10
59230 jack 3
222 hacker 9999
id 資料儲存在 key 名為 user_id 的列表中。
name 資料儲存在 key 名為 user_name_{id} 的列表中
level 資料儲存在 user_level_{id} 的 key 中。
示例程式碼:
# 先將要使用的資料加入到資料庫中
# admin
redis> LPUSH user_id 1
(integer) 1
redis> SET user_name_1 admin
OK
redis> SET user_level_1 9999
OK
# huangz
redis> LPUSH user_id 2
(integer) 2
redis> SET user_name_2 huangz
OK
redis> SET user_level_2 10
OK
# jack
redis> LPUSH user_id 59230
(integer) 3
redis> SET user_name_59230 jack
OK
redis> SET user_level_59230 3
OK
# hacker
redis> LPUSH user_id 222
(integer) 4
redis> SET user_name_222 hacker
OK
redis> SET user_level_222 9999
OK
如果希望按 level 從大到小排序 user_id ,可以使用以下命令:
redis> SORT user_id BY user_level_* DESC
1) "222" # hacker
2) "1" # admin
3) "2" # huangz
4) "59230" # jack
但是有時候只是返回相應的 id 沒有什麼用,你可能更希望排序後返回 id 對應的使用者
名,這樣更友好一點,使用 GET 選項可以做到這一點:
redis> SORT user_id BY user_level_* DESC GET user_name_*
1) "hacker"
2) "admin"
3) "huangz"
4) "jack"
可以多次地、有序地使用 GET 操作來獲取更多外部 key 。
比如你不但希望獲取使用者名稱,還希望連使用者的密碼也一併列出,可以使用以下命令:
# 先新增一些測試資料
redis> SET user_password_222 "hey,im in"
OK
redis> SET user_password_1 "a_long_long_password"
OK
redis> SET user_password_2 "nobodyknows"
OK
redis> SET user_password_59230 "jack201022"
OK
# 獲取name 和password
redis> SORT user_id BY user_level_* DESC GET user_name_* GET
user_password_*
1) "hacker" # 使用者名稱
2) "hey,im in" # 密碼
3) "jack"
4) "jack201022"
5) "huangz"
6) "nobodyknows"
7) "admin"
8) "a_long_long_password"
# 注意GET 操作是有序的,GET user_name_* GET user_password_* 和 GET
user_password_* GET user_name_*返回的結果位置不同
redis> SORT user_id BY user_level_* DESC GET user_password_* GET
user_name_*
1) "hey,im in" # 密碼
2) "hacker" # 使用者名稱
3) "jack201022"
4) "jack"
5) "nobodyknows"
6) "huangz"
7) "a_long_long_password"
8) "admin"
GET 還有一個特殊的規則—— "GET #" ,用於獲取被排序物件(我們這裡的例子是
user_id )的當前元素。
比如你希望 user_id 按 level 排序,還要列出 id 、 name 和 password ,可以使用
以下命令:
redis> SORT user_id BY user_level_* DESC GET # GET user_name_* GET
user_password_*
1) "222" # id
2) "hacker" # name
3) "hey,im in" # password
4) "1"
5) "admin"
6) "a_long_long_password"
7) "2"
8) "huangz"
9) "nobodyknows"
10) "59230"
11) "jack"
12) "jack201022"
只獲取物件而不排序
BY 修飾符可以將一個不存在的 key 當作權重,讓 SORT 跳過排序操作。
該方法用於你希望獲取外部物件而又不希望引起排序開銷時使用。
# 確保fake_key 不存在
redis> EXISTS fake_key
(integer) 0
# 以fake_key 作BY 引數,不排序,只GET name 和 GET password
redis> SORT user_id BY fake_key GET # GET user_name_* GET
user_password_*
1) "222" # id
2) "hacker" # user_name
3) "hey,im in" # password
4) "59230"
5) "jack"
6) "jack201022"
7) "2"
8) "huangz"
9) "nobodyknows"
10) "1"
11) "admin"
12) "a_long_long_password"
儲存排序結果
預設情況下, SORT 操作只是簡單地返回排序結果,如果你希望儲存排序結果,可以給
STORE 選項指定一個 key 作為引數,排序結果將以列表的形式被儲存到這個 key 上。(若
指定 key 已存在,則覆蓋。)
redis> EXISTS user_info_sorted_by_level # 確保指定key 不存在
(integer) 0
redis> SORT user_id BY user_level_* GET # GET user_name_* GET
user_password_* STORE user_info_sorted_by_level # 排序
(integer) 12 # 顯示有12 條結果被儲存了
redis> LRANGE user_info_sorted_by_level 0 11 # 檢視排序結果
1) "59230"
2) "jack"
3) "jack201022"
4) "2"
5) "huangz"
6) "nobodyknows"
7) "222"
8) "hacker"
9) "hey,im in"
10) "1"
11) "admin"
12) "a_long_long_password"
一個有趣的用法是將 SORT 結果儲存,用 EXPIRE 為結果集設定生存時間,這樣結果集
就成了 SORT 操作的一個快取。
這樣就不必頻繁地呼叫 SORT 操作了,只有當結果集過期時,才需要再呼叫一次 SORT
操作。
有時候為了正確實現這一用法,你可能需要加鎖以避免多個客戶端同時進行快取重建
(也就是多個客戶端,同一時間進行 SORT 操作,並儲存為結果集),具體參見 SETNX 命令。
在GET 和BY 中使用雜湊表
可以使用雜湊表特有的語法,在 SORT 命令中進行 GET 和 BY 操作。
# 假設現在我們的使用者表新增了一個 serial 項來為作為每個使用者的序列號
# 序列號以雜湊表的形式儲存在 serial 雜湊域內。
redis> HMSET serial 1 23131283 2 23810573 222 502342349 59230
2435829758
OK
# 用 serial 中值的大小為根據,對 user_id 進行排序
redis> SORT user_id BY *->serial
1) "59230"
2) "222"
3) "2"
4) "1"
符號 "->" 用於分割雜湊表的鍵名(key name)和索引域(hash field),格式為
"key->field" 。
除此之外,雜湊表的 BY 和 GET 操作和上面介紹的其他資料結構(列表、集合、有序集
合)沒有什麼不同。
可用版本:
>= 1.0.0
時間複雜度:
O(N+M*log(M)), N 為要排序的列表或集合內的元素數量, M 為要返回的元素數量。
如果只是使用 SORT 命令的 GET 選項獲取資料而沒有進行排序,時間複雜度 O(N)。
返回值:
沒有使用 STORE 引數,返回列表形式的排序結果。
使用 STORE 引數,返回排序結果的元素數量。
OBJECT
格式:object subcommand [arguments [arguments]]
OBJECT 命令允許從內部察看給定 key 的 Redis 物件。
它通常用在除錯(debugging)或者瞭解為了節省空間而對 key 使用特殊編碼的情況。
當將Redis 用作快取程式時,你也可以通過 OBJECT 命令中的資訊,決定 key 的驅逐
策略(eviction policies)。
OBJECT 命令有多個子命令:
 OBJECT REFCOUNT <key> 返回給定 key 引用所儲存的值的次數。此命令主要用於
除錯。
 OBJECT ENCODING <key> 返回給定 key 鎖儲存的值所使用的內部表示
(representation)。
 OBJECT IDLETIME <key> 返回給定 key 自儲存以來的空轉時間(idle, 沒有被讀
取也沒有被寫入),以秒為單位。
物件可以以多種方式編碼:
 字串可以被編碼為 raw (一般字串)或 int (用字串表示64 位數字是為了節
約空間)。
 列表可以被編碼為 ziplist 或 linkedlist 。 ziplist 是為節約大小較小的列表
空間而作的特殊表示。
 集合可以被編碼為 intset 或者 hashtable 。 intset 是隻儲存數字的小集合的
特殊表示。
 雜湊表可以編碼為 zipmap 或者 hashtable 。 zipmap 是小雜湊表的特殊表示。
 有序集合可以被編碼為 ziplist 或者 skiplist 格式。 ziplist 用於表示小的有
序集合,而 skiplist 則用於表示任何大小的有序集合。
假如你做了什麼讓 Redis 沒辦法再使用節省空間的編碼時(比如將一個只有 1 個元素
的集合擴充套件為一個有 100 萬個元素的集合),特殊編碼型別(specially encoded types)會
自動轉換成通用型別(general type)。
可用版本:
>= 2.2.3
時間複雜度:
O(1)
返回值:
REFCOUNT 和 IDLETIME 返回數字。
ENCODING 返回相應的編碼型別。
示例程式碼:
redis> SET game "COD" # 設定一個字串
OK
redis> OBJECT REFCOUNT game # 只有一個引用
(integer) 1
redis> OBJECT IDLETIME game # 等待一陣。。。然後檢視空轉時間
(integer) 90
redis> GET game # 提取game, 讓它處於活躍(active)狀態
"COD"
redis> OBJECT IDLETIME game # 不再處於空轉
(integer) 0
redis> OBJECT ENCODING game # 字串的編碼方式
"raw"
redis> SET phone 15820123123 # 大的數字也被編碼為字串
OK
redis> OBJECT ENCODING phone
"raw"
redis> SET age 20 # 短數字被編碼為 int
OK
redis> OBJECT ENCODING age
"int"
MIGRATE
格式:migrate host port key destination-db timeout
將 key 原子性地從當前例項傳送到目標例項的指定資料庫上,一旦傳送成功, key 保
證會出現在目標例項上,而當前例項上的 key 會被刪除。
這個命令是一個原子操作,它在執行的時候會阻塞進行遷移的兩個例項,直到以下任意
結果發生:遷移成功,遷移失敗,等到超時。
命令的內部實現是這樣的:它在當前例項對給定 key 執行 DUMP 命令 ,將它序列化,
然後傳送到目標例項,目標例項再使用 RESTORE 對資料進行反序列化,並將反序列化所得
的資料新增到資料庫中;當前例項就像目標例項的客戶端那樣,只要看到 RESTORE 命令返
回 OK ,它就會呼叫 DEL 刪除自己資料庫上的 key 。
timeout 引數以毫秒為格式,指定當前例項和目標例項進行溝通的最大間隔時間。這說
明操作並不一定要在 timeout 毫秒內完成,只是說資料傳送的時間不能超過這個 timeout
數。
MIGRATE 命令需要在給定的時間規定內完成 IO 操作。如果在傳送資料時發生 IO 錯誤,
或者達到了超時時間,那麼命令會停止執行,並返回一個特殊的錯誤: IOERR 。
當 IOERR 出現時,有以下兩種可能:
 key 可能存在於兩個例項
 key 可能只存在於當前例項
唯一不可能發生的情況就是丟失 key ,因此,如果一個客戶端執行 MIGRATE 命令,並
且不幸遇上 IOERR 錯誤,那麼這個客戶端唯一要做的就是檢查自己資料庫上的 key 是否已
經被正確地刪除。
如果有其他錯誤發生,那麼MIGRATE 保證 key 只會出現在當前例項中。(當然,目標
例項的給定資料庫上可能有和 key 同名的鍵,不過這和 MIGRATE 命令沒有關係)。
可用版本:
>= 2.6.0
時間複雜度:
這個命令在源例項上實際執行 DUMP 命令和 DEL 命令,在目標例項執行 RESTORE 命令,
檢視以上命令的文件可以看到詳細的複雜度說明。
key 資料在兩個例項之間傳輸的複雜度為 O(N) 。
返回值:
遷移成功時返回 OK ,否則返回相應的錯誤。
示例
先啟動兩個 Redis 例項,一個使用預設的 6379 埠,一個使用 7777 埠。
$ ./redis-server &
[1] 3557
...
$ ./redis-server --port 7777 &
[2] 3560
...
然後用客戶端連上 6379 埠的例項,設定一個鍵,然後將它遷移到 7777 埠的例項上:
$ ./redis-cli
redis 127.0.0.1:6379> flushdb
OK
redis 127.0.0.1:6379> SET greeting "Hello from 6379 instance"
OK
redis 127.0.0.1:6379> MIGRATE 127.0.0.1 7777 greeting 0 1000
OK
redis 127.0.0.1:6379> EXISTS greeting # 遷移成功後 key 被刪除
(integer) 0
使用另一個客戶端,檢視 7777 埠上的例項:
$ ./redis-cli -p 7777
redis 127.0.0.1:7777> GET greeting
"Hello from 6379 instance"
DUMP
格式:dump key
序列化給定 key ,並返回被序列化的值,使用 RESTORE 命令可以將這個值反序列化為
Redis 鍵。
序列化生成的值有以下幾個特點:
 它帶有 64 位的校驗和,用於檢測錯誤, RESTORE 在進行反序列化之前會先檢查
校驗和。
 值的編碼格式和 RDB 檔案保持一致。
 RDB 版本會被編碼在序列化值當中,如果因為 Redis 的版本不同造成 RDB 格式不
相容,那麼 Redis 會拒絕對這個值進行反序列化操作。
序列化的值不包括任何生存時間資訊。
可用版本:
>= 2.6.0
時間複雜度:
查詢給定鍵的複雜度為 O(1) ,對鍵進行序列化的複雜度為 O(N*M) ,其中 N 是構成
key 的 Redis 物件的數量,而 M 則是這些物件的平均大小。
如果序列化的物件是比較小的字串,那麼複雜度為 O(1) 。
返回值:
如果 key 不存在,那麼返回 nil 。
否則,返回序列化之後的值。
示例程式碼:
redis> SET greeting "hello, dumping world!"
OK
redis> DUMP greeting
"\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde"
redis> DUMP not-exists-key
(nil)
RESTORE
格式:restore key ttl serialized-value
反序列化給定的序列化值,並將它和給定的 key 關聯。
引數 ttl 以毫秒為單位為 key 設定生存時間;如果 ttl 為 0 ,那麼不設定生存時間。
RESTORE 在執行反序列化之前會先對序列化值的 RDB 版本和資料校驗和進行檢查,如
果 RDB 版本不相同或者資料不完整的話,那麼 RESTORE 會拒絕進行反序列化,並返回一個
錯誤。
更多資訊可以參考 DUMP 命令。
可用版本:
>= 2.6.0
時間複雜度:
查詢給定鍵的複雜度為 O(1) ,對鍵進行反序列化的複雜度為 O(N*M) ,其中 N 是構
成 key 的 Redis 物件的數量,而 M 則是這些物件的平均大小。
有序集合(sorted set)的反序列化複雜度為 O(N*M*log(N)) ,因為有序集合每次插入
的複雜度為 O(log(N)) 。
如果反序列化的物件是比較小的字串,那麼複雜度為 O(1) 。
返回值:
如果反序列化成功那麼返回 OK ,否則返回一個錯誤。
示例程式碼:
redis> SET greeting "hello, dumping world!"
OK
redis> DUMP greeting
"\x00\x15hello, dumping world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde"
redis> RESTORE greeting-again 0 "\x00\x15hello, dumping
world!\x06\x00E\xa0Z\x82\xd8r\xc1\xde"
OK
redis> GET greeting-again
"hello, dumping world!"
redis> RESTORE fake-message 0 "hello moto moto blah blah" ; 使用錯
誤的值進行反序列化
(error) ERR DUMP payload version or checksum are wrong
String(字串)
SET
格式:set key value
將字串值 value 關聯到 key 。
如果 key 已經持有其他值, SET 就覆寫舊值,無視型別。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
總是返回 OK ,因為 SET 不可能失敗。
程式碼示例:
# 對字串型別的 key 進行 SET
redis> SET apple www.apple.com
OK
redis> GET apple
"www.apple.com"
# 對非字串型別的 key 進行 SET
redis> LPUSH greet_list "hello" # 建立一個列表
(integer) 1
redis> TYPE greet_list
list
redis> SET greet_list "yooooooooooooooooo" # 覆蓋列表型別
OK
redis> TYPE greet_list
string
SETNX
格式:setnx key value
將 key 的值設為 value ,當且僅當 key 不存在。
若給定的 key 已經存在,則 SETNX 不做任何動作。
SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
設定成功,返回 1 。
設定失敗,返回 0 。
示例程式碼:
redis> EXISTS job # job 不存在
(integer) 0
redis> SETNX job "programmer" # job 設定成功
(integer) 1
redis> SETNX job "code-farmer" # 嘗試覆蓋 job ,失敗
(integer) 0
redis> GET job # 沒有被覆蓋
"programmer"
模式:將 SETNX 用於加鎖(locking)
警告:已經證實這個加鎖演算法帶有競爭條件,在特定情況下會造成錯誤,請不要使用這
個加鎖演算法。
SETNX 可以用作加鎖原語(locking primitive)。比如說,要對關鍵字(key) foo 加鎖,
客戶端可以嘗試以下方式:
SETNX lock.foo <current Unix time + lock timeout + 1>
如果 SETNX 返回 1 ,說明客戶端已經獲得了鎖, key 設定的unix 時間則指定了鎖失
效的時間。之後客戶端可以通過 DEL lock.foo 來釋放鎖。
如果 SETNX 返回 0 ,說明 key 已經被其他客戶端上鎖了。如果鎖是非阻塞(non
blocking lock)的,我們可以選擇返回呼叫,或者進入一個重試迴圈,直到成功獲得鎖或重
試超時(timeout)。
處理死鎖(deadlock)
上面的鎖演算法有一個問題:如果因為客戶端失敗、崩潰或其他原因導致沒有辦法釋放鎖
的話,怎麼辦?
這種狀況可以通過檢測發現——因為上鎖的 key 儲存的是 unix 時間戳,假如 key 值
的時間戳小於當前的時間戳,表示鎖已經不再有效。
但是,當有多個客戶端同時檢測一個鎖是否過期並嘗試釋放它的時候,我們不能簡單粗
暴地刪除死鎖的 key ,再用 SETNX 上鎖,因為這時競爭條件(race condition)已經形成了:
 C1 和 C2 讀取 lock.foo 並檢查時間戳, SETNX 都返回 0 ,因為它已經被 C3 鎖
上了,但 C3 在上鎖之後就崩潰(crashed)了。
 C1 向 lock.foo 傳送 DEL 命令。
 C1 向 lock.foo 傳送 SETNX 併成功。
 C2 向 lock.foo 傳送 DEL 命令。
 C2 向 lock.foo 傳送 SETNX 併成功。
 出錯:因為競爭條件的關係,C1 和 C2 兩個都獲得了鎖。
幸好,以下演算法可以避免以上問題。來看看我們聰明的 C4 客戶端怎麼辦:
 C4 向 lock.foo 傳送 SETNX 命令。
 因為崩潰掉的 C3 還鎖著 lock.foo ,所以 Redis 向 C4 返回 0 。
 C4 向 lock.foo 傳送 GET 命令,檢視 lock.foo 的鎖是否過期。如果不,則休眠
(sleep)一段時間,並在之後重試。
 另一方面,如果 lock.foo 內的 unix 時間戳比當前時間戳老,C4 執行以下命令:
GETSET lock.foo <current Unix timestamp + lock timeout + 1>
 因為 GETSET 的作用,C4 可以檢檢視 GETSET 的返回值,確定 lock.foo 之前儲
存的舊值仍是那個過期時間戳,如果是的話,那麼 C4 獲得鎖。
 如果其他客戶端,比如 C5,比 C4 更快地執行了 GETSET 操作並獲得鎖,那麼 C4
的 GETSET 操作返回的就是一個未過期的時間戳(C5 設定的時間戳)。C4 只好從第
一步開始重試。
注意,即便 C4 的 GETSET 操作對 key 進行了修改,這對未來也沒什麼影響。
警告:為了讓這個加鎖演算法更健壯,獲得鎖的客戶端應該常常檢查過期時間以免鎖因諸
如 DEL 等命令的執行而被意外解開,因為客戶端失敗的情況非常複雜,不僅僅是崩潰這麼
簡單,還可能是客戶端因為某些操作被阻塞了相當長時間,緊接著 DEL 命令被嘗試執行(但
這時鎖卻在另外的客戶端手上)。
SETEX
格式:setex key seconds value
將值 value 關聯到 key ,並將 key 的生存時間設為 seconds (以秒為單位)。
如果 key 已經存在, SETEX 命令將覆寫舊值。
這個命令類似於以下兩個命令:
SET key value
EXPIRE key seconds # 設定生存時間
不同之處是, SETEX 是一個原子性(atomic)操作,關聯值和設定生存時間兩個動作會
在同一時間內完成,該命令在 Redis 用作快取時,非常實用。
可用版本:
>= 2.0.0
時間複雜度:
O(1)
返回值:
設定成功時返回 OK 。
當 seconds 引數不合法時,返回一個錯誤。
示例程式碼:
# 在 key 不存在時進行 SETEX
redis> SETEX cache_user_id 60 10086
OK
redis> GET cache_user_id # 值
"10086"
redis> TTL cache_user_id # 剩餘生存時間
(integer) 49
# key 已經存在時,SETEX 覆蓋舊值
redis> SET cd "timeless"
OK
redis> SETEX cd 3000 "goodbye my love"
OK
redis> GET cd
"goodbye my love"
redis> TTL cd
(integer) 2997
PSETEX
格式:psetex key milliseconds value
這個命令和 SETEX 命令相似,但它以毫秒為單位設定 key 的生存時間,而不是像
SETEX 命令那樣,以秒為單位。
可用版本:
>= 2.6.0
時間複雜度:
O(1)
返回值:
設定成功時返回 OK 。
示例程式碼:
redis> PSETEX mykey 1000 "Hello"
OK
redis> PTTL mykey
(integer) 999
redis> GET mykey
"Hello"
SETRANGE
格式:setrange key offset value
用 value 引數覆寫(overwrite)給定 key 所儲存的字串值,從偏移量 offset 開始。
不存在的 key 當作空白字串處理。
SETRANGE 命令會確保字串足夠長以便將 value 設定在指定的偏移量上,如果給定
key 原來儲存的字串長度比偏移量小(比如字串只有 5 個字元長,但你設定的 offset
是 10 ),那麼原字元和偏移量之間的空白將用零位元組(zerobytes, "\x00" )來填充。
注意你能使用的最大偏移量是 2^29-1(536870911) ,因為 Redis 字串的大小被限制
在 512 兆(megabytes)以內。如果你需要使用比這更大的空間,你可以使用多個 key 。
警告:當生成一個很長的字串時,Redis 需要分配記憶體空間,該操作有時候可能會造
成伺服器阻塞(block)。在2010 年的Macbook Pro 上,設定偏移量為 536870911(512MB 內
存分配),耗費約 300 毫秒,設定偏移量為 134217728(128MB 記憶體分配),耗費約 80 毫秒,
設定偏移量 33554432(32MB 記憶體分配),耗費約 30 毫秒,設定偏移量為 8388608(8MB 內
存分配),耗費約 8 毫秒。注意若首次記憶體分配成功之後,再對同一個 key 呼叫 SETRANGE
操作,無須再重新記憶體。
可用版本:
>= 2.2.0
時間複雜度:
對小(small)的字串,平攤複雜度O(1)。(關於什麼字串是”小”的,請參考 APPEND
命令)
否則為O(M), M 為 value 引數的長度。
返回值:
被 SETRANGE 修改之後,字串的長度。
示例程式碼:
# 對非空字串進行 SETRANGE
redis> SET greeting "hello world"
OK
redis> SETRANGE greeting 6 "Redis"
(integer) 11
redis> GET greeting
"hello Redis"
# 對空字串/不存在的 key 進行 SETRANGE
redis> EXISTS empty_string
(integer) 0
redis> SETRANGE empty_string 5 "Redis!" # 對不存在的 key 使用
SETRANGE
(integer) 11
redis> GET empty_string # 空白處被"\x00"填充
"\x00\x00\x00\x00\x00Redis!"
模式
因為有了 SETRANGE 和 GETRANGE 命令,你可以將 Redis 字串用作具有O(1)隨機訪
問時間的線性陣列,這在很多真實用例中都是非常快速且高效的儲存方式,具體請參考
APPEND 命令的『模式:時間序列』部分。
MSET
格式:mset key value [key value ...]
同時設定一個或多個 key-value 對。
如果某個給定 key 已經存在,那麼 MSET 會用新值覆蓋原來的舊值,如果這不是你所
希望的效果,請考慮使用 MSETNX 命令:它只會在所有給定 key 都不存在的情況下進行設
置操作。
MSET 是一個原子性(atomic)操作,所有給定 key 都會在同一時間內被設定,某些給定
key 被更新而另一些給定 key 沒有改變的情況,不可能發生。
可用版本:
>= 1.0.1
時間複雜度:
O(N), N 為要設定的 key 數量。
返回值:
總是返回 OK (因為 MSET 不可能失敗)
示例程式碼:
redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny"
OK
redis> MGET date time weather
1) "2012.3.30"
2) "11:00 a.m."
3) "sunny"
# MSET 覆蓋舊值例子
redis> SET google "google.hk"
OK
redis> MSET google "google.com"
OK
redis> GET google
"google.com"
MSETNX
格式:msetnx key value [key value ...]
同時設定一個或多個 key-value 對,當且僅當所有給定 key 都不存在。
即使只有一個給定 key 已存在, MSETNX 也會拒絕執行所有給定 key 的設定操作。
MSETNX 是原子性的,因此它可以用作設定多個不同 key 表示不同欄位(field)的唯一
性邏輯物件(unique logic object),所有欄位要麼全被設定,要麼全不被設定。
可用版本:
>= 1.0.1
時間複雜度:
O(N), N 為要設定的 key 的數量。
返回值:
當所有 key 都成功設定,返回 1 。
如果所有給定 key 都設定失敗(至少有一個 key 已經存在),那麼返回 0 。
示例程式碼:
# 對不存在的 key 進行 MSETNX
redis> MSETNX rmdbs "MySQL" nosql "MongoDB" key-value-store "redis"
(integer) 1
redis> MGET rmdbs nosql key-value-store
1) "MySQL"
2) "MongoDB"
3) "redis"
# MSET 的給定 key 當中有已存在的 key
redis> MSETNX rmdbs "Sqlite" language "python" # rmdbs 鍵已經存在,
操作失敗
(integer) 0
redis> EXISTS language # 因為 MSET 是原子性操作,language 沒有被設定
(integer) 0
redis> GET rmdbs # rmdbs 也沒有被修改
"MySQL"
APPEND
格式:append key value
如果 key 已經存在並且是一個字串, APPEND 命令將 value 追加到 key 原來的值
的末尾。
如果 key 不存在, APPEND 就簡單地將給定 key 設為 value ,就像執行 SET key
value 一樣。
可用版本:
>= 2.0.0
時間複雜度:
平攤O(1)
返回值:
追加 value 之後, key 中字串的長度。
示例程式碼:
# 對不存在的 key 執行 APPEND
redis> EXISTS myphone # 確保 myphone 不存在
(integer) 0
redis> APPEND myphone "nokia" # 對不存在的 key 進行 APPEND ,等同
於 SET myphone "nokia"
(integer) 5 # 字元長度
# 對已存在的字串進行 APPEN
redis> APPEND myphone " - 1110" # 長度從 5 個字元增加到 12 個字元
(integer) 12
redis> GET myphone
"nokia - 1110"
模式:時間序列(Time series)
APPEND 可以為一系列定長(fixed-size)資料(sample)提供一種緊湊的表示方式,通常
稱之為時間序列。
每當一個新資料到達的時候,執行以下命令:
APPEND timeseries "fixed-size sample"
然後可以通過以下的方式訪問時間序列的各項屬性:
 STRLEN 給出時間序列中資料的數量
 GETRANGE 可以用於隨機訪問。只要有相關的時間資訊的話,我們就可以在 Redis
2.6 中使用 Lua 指令碼和 GETRANGE 命令實現二分查詢。
 SETRANGE 可以用於覆蓋或修改已存在的的時間序列。
這個模式的唯一缺陷是我們只能增長時間序列,而不能對時間序列進行縮短,因為
Redis 目前還沒有對字串進行修剪(tirm)的命令,但是,不管怎麼說,這個模式的儲存方
式還是可以節省下大量的空間。
注:可以考慮使用 UNIX 時間戳作為時間序列的鍵名,這樣一來,可以避免單個 key 因
為儲存過大的時間序列而佔用大量記憶體,另一方面,也可以節省下大量名稱空間。
下面是一個時間序列的例子:
redis> APPEND ts "0043"
(integer) 4
redis> APPEND ts "0035"
(integer) 8
redis> GETRANGE ts 0 3
"0043"
redis> GETRANGE ts 4 7
"0035"
GET
格式:get key
返回 key 所關聯的字串值。
如果 key 不存在那麼返回特殊值 nil 。
假如 key 儲存的值不是字串型別,返回一個錯誤,因為 GET 只能用於處理字串值。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
當 key 不存在時,返回 nil ,否則,返回 key 的值。
如果 key 不是字串型別,那麼返回一個錯誤。
示例程式碼:
# 對不存在的 key 或字串型別 key 進行 GET
redis> GET db
(nil)
redis> SET db redis
OK
redis> GET db
"redis"
# 對不是字串型別的 key 進行 GET
redis> DEL db
(integer) 1
redis> LPUSH db redis mongodb mysql
(integer) 3
redis> GET db
(error) ERR Operation against a key holding the wrong kind of value
MGET
格式:mget key [key ...]
返回所有(一個或多個)給定 key 的值。
如果給定的 key 裡面,有某個 key 不存在,那麼這個 key 返回特殊值 nil 。因此,
該命令永不失敗。
可用版本:
>= 1.0.0
時間複雜度:
O(N) , N 為給定 key 的數量。
返回值:
一個包含所有給定 key 的值的列表。
示例程式碼:
redis> SET redis redis.com
OK
redis> SET mongodb mongodb.org
OK
redis> MGET redis mongodb
1) "redis.com"
2) "mongodb.org"
redis> MGET redis mongodb mysql # 不存在的 mysql 返回 nil
1) "redis.com"
2) "mongodb.org"
3) (nil)
GETRANGE
格式:getrange key start end
返回 key 中字串值的子字串,字串的擷取範圍由 start 和 end 兩個偏移量決
定(包括 start 和 end 在內)。
負數偏移量表示從字串最後開始計數, -1 表示最後一個字元, -2 表示倒數第二個,
以此類推。
GETRANGE 通過保證子字串的值域(range)不超過實際字串的值域來處理超出範圍
的值域請求。
注:在 <= 2.0 的版本里,GETRANGE 被叫作 SUBSTR。
可用版本:
>= 2.4.0
時間複雜度:
O(N), N 為要返回的字串的長度。
複雜度最終由字串的返回值長度決定,但因為從已有字串中取出子字串的操作非
常廉價(cheap),所以對於長度不大的字串,該操作的複雜度也可看作O(1)。
返回值:
擷取得出的子字串。
示例程式碼:
redis> SET greeting "hello, my friend"
OK
redis> GETRANGE greeting 0 4 # 返回索引0-4 的字元,包括4。
"hello"
redis> GETRANGE greeting -1 -5 # 不支援迴繞操作
""
redis> GETRANGE greeting -3 -1 # 負數索引
"end"
redis> GETRANGE greeting 0 -1 # 從第一個到最後一個
"hello, my friend"
redis> GETRANGE greeting 0 1008611 # 值域範圍不超過實際字串,超過部分
自動被符略
"hello, my friend"
GETSET
格式:getset key value
將給定 key 的值設為 value ,並返回 key 的舊值(old value)。
當 key 存在但不是字串型別時,返回一個錯誤。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
返回給定 key 的舊值。
當 key 沒有舊值時,也即是, key 不存在時,返回 nil 。
示例程式碼:
redis> GETSET db mongodb # 沒有舊值,返回 nil
(nil)
redis> GET db
"mongodb"
redis> GETSET db redis # 返回舊值 mongodb
"mongodb"
redis> GET db
"redis"
模式
GETSET 可以和 INCR 組合使用,實現一個有原子性(atomic)復位操作的計數器
(counter)。
舉例來說,每次當某個事件發生時,程序可能對一個名為 mycount 的 key 呼叫 INCR
操作,通常我們還要在一個原子時間內同時完成獲得計數器的值和將計數器值復位為 0 兩
個操作。
可以用命令 GETSET mycounter 0 來實現這一目標。
redis> INCR mycount
(integer) 11
redis> GETSET mycount 0 # 一個原子內完成 GET mycount 和 SET mycount 0
操作
"11"
redis> GET mycount # 計數器被重置
"0"
STRLEN
格式:strlen key
返回 key 所儲存的字串值的長度。
當 key 儲存的不是字串值時,返回一個錯誤。
可用版本:
>= 2.2.0
複雜度:
O(1)
返回值:
字串值的長度。
當 key 不存在時,返回 0 。
示例程式碼:
# 獲取字串的長度
redis> SET mykey "Hello world"
OK
redis> STRLEN mykey
(integer) 11
# 不存在的 key 長度為 0
redis> STRLEN nonexisting
(integer) 0
DECR
格式:decr key
將 key 中儲存的數字值減一。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 DECR 操作。
如果值包含錯誤的型別,或字串型別的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位(bit)有符號數字表示之內。
關於遞增(increment) / 遞減(decrement)操作的更多資訊,請參見 INCR 命令。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
執行 DECR 命令之後 key 的值。
示例程式碼:
# 對存在的數字值 key 進行 DECR
redis> SET failure_times 10
OK
redis> DECR failure_times
(integer) 9
# 對不存在的 key 值進行 DECR
redis> EXISTS count
(integer) 0
redis> DECR count
(integer) -1
# 對存在但不是數值的 key 進行 DECR
redis> SET company YOUR_CODE_SUCKS.LLC
OK
redis> DECR company
(error) ERR value is not an integer or out of range
DECRBY
格式:decrby key decrement
將 key 所儲存的值減去減量 decrement 。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 DECRBY 操作。
如果值包含錯誤的型別,或字串型別的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位(bit)有符號數字表示之內。
關於更多遞增(increment) / 遞減(decrement)操作的更多資訊,請參見 INCR 命令。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
減去 decrement 之後, key 的值。
示例程式碼:
# 對已存在的 key 進行 DECRBY
redis> SET count 100
OK
redis> DECRBY count 20
(integer) 80
# 對不存在的 key 進行DECRBY
redis> EXISTS pages
(integer) 0
redis> DECRBY pages 10
(integer) -10
INCR
格式:incr key
將 key 中儲存的數字值增一。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 INCR 操作。
如果值包含錯誤的型別,或字串型別的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位(bit)有符號數字表示之內。
注:這是一個針對字串的操作,因為 Redis 沒有專用的整數型別,所以 key 內儲存
的字串被解釋為十進位制 64 位有符號整數來執行 INCR 操作。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
執行 INCR 命令之後 key 的值。
示例程式碼:
redis> SET page_view 20
OK
redis> INCR page_view
(integer) 21
redis> GET page_view # 數字值在 Redis 中以字串的形式儲存
"21"
模式:計數器
計數器是 Redis 的原子性自增操作可實現的最直觀的模式了,它的想法相當簡單:每
當某個操作發生時,向 Redis 傳送一個 INCR 命令。
比如在一個 web 應用程式中,如果想知道使用者在一年中每天的點選量,那麼只要將用
戶 ID 以及相關的日期資訊作為鍵,並在每次使用者點選頁面時,執行一次自增操作即可。
比如使用者名稱是 peter ,點選時間是 2012 年 3 月 22 日,那麼執行命令:
INCR peter::2012.3.22 。
可以用以下幾種方式擴充套件這個簡單的模式:
 可以通過組合使用 INCR 和 EXPIRE ,來達到只在規定的生存時間內進行計數
(counting)的目的。
 客戶端可以通過使用 GETSET 命令原子性地獲取計數器的當前值並將計數器清零,
更多資訊請參考 GETSET 命令。
 使用其他自增/自減操作,比如 DECR 和 INCRBY ,使用者可以通過執行不同的操作
增加或減少計數器的值,比如在遊戲中的記分器就可能用到這些命令。
模式:限速器
限速器是特殊化的計算器,它用於限制一個操作可以被執行的速率(rate)。
限速器的典型用法是限制公開 API 的請求次數,以下是一個限速器實現示例,它將 API
的最大請求數限制在每個 IP 地址每秒鐘十個之內:
FUNCTION LIMIT_API_CALL(ip)
ts = CURRENT_UNIX_TIME()
keyname = ip+":"+ts
current = GET(keyname)
IF current != NULL AND current > 10 THEN
ERROR "too many requests per second"
END
IF current == NULL THEN
MULTI
INCR(keyname, 1)
EXPIRE(keyname, 1)
EXEC
ELSE
INCR(keyname, 1)
END
PERFORM_API_CALL()
這個實現每秒鐘為每個 IP 地址使用一個不同的計數器,並用 EXPIRE 命令設定生存時
間(這樣 Redis 就會負責自動刪除過期的計數器)。
注意,我們使用事務打包執行 INCR 命令和 EXPIRE 命令,避免引入競爭條件,保證每
次呼叫 API 時都可以正確地對計數器進行自增操作並設定生存時間。
以下是另一個限速器實現:
FUNCTION LIMIT_API_CALL(ip):
current = GET(ip)
IF current != NULL AND current > 10 THEN
ERROR "too many requests per second"
ELSE
value = INCR(ip)
IF value == 1 THEN
EXPIRE(ip,1)
END
PERFORM_API_CALL()
END
這個限速器只使用單個計數器,它的生存時間為一秒鐘,如果在一秒鐘內,這個計數器
的值大於 10 的話,那麼訪問就會被禁止。
這個新的限速器在思路方面是沒有問題的,但它在實現方面不夠嚴謹,如果我們仔細觀
察一下的話,就會發現在 INCR 和 EXPIRE 之間存在著一個競爭條件,假如客戶端在執行
INCR 之後,因為某些原因(比如客戶端失敗)而忘記設定 EXPIRE 的話,那麼這個計數器就
會一直存在下去,造成每個使用者只能訪問 10 次,噢,這簡直是個災難!
要消滅這個實現中的競爭條件,我們可以將它轉化為一個 Lua 指令碼,並放到 Redis 中
執行(這個方法僅限於 Redis 2.6 及以上的版本):
local current
current = redis.call("incr",KEYS[1])
if tonumber(current) == 1 then
redis.call("expire",KEYS[1],1)
end
通過將計數器作為指令碼放到 Redis 上執行,我們保證了 INCR 和 EXPIRE 兩個操作的
原子性,現在這個指令碼實現不會引入競爭條件,它可以運作的很好。
關於在 Redis 中執行 Lua 指令碼的更多資訊,請參考 EVAL 命令。
還有另一種消滅競爭條件的方法,就是使用 Redis 的列表結構來代替 INCR 命令,這
個方法無須指令碼支援,因此它在 Redis 2.6 以下的版本也可以執行得很好:
FUNCTION LIMIT_API_CALL(ip)
current = LLEN(ip)
IF current > 10 THEN
ERROR "too many requests per second"
ELSE
IF EXISTS(ip) == FALSE
MULTI
RPUSH(ip,ip)
EXPIRE(ip,1)
EXEC
ELSE
RPUSHX(ip,ip)
END
PERFORM_API_CALL()
END
新的限速器使用了列表結構作為容器, LLEN 用於對訪問次數進行檢查,一個事務包裹
著 RPUSH 和 EXPIRE 兩個命令,用於在第一次執行計數時建立列表,並正確設定地設定過
期時間,最後, RPUSHX 在後續的計數操作中進行增加操作。
INCRBY
格式:incrby key increment
將 key 所儲存的值加上增量 increment 。
如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 INCRBY 命令。
如果值包含錯誤的型別,或字串型別的值不能表示為數字,那麼返回一個錯誤。
本操作的值限制在 64 位(bit)有符號數字表示之內。
關於遞增(increment) / 遞減(decrement)操作的更多資訊,參見 INCR 命令。
可用版本:
>= 1.0.0
時間複雜度:
O(1)
返回值:
加上 increment 之後, key 的值。
示例程式碼:
# key 存在且是數字值
redis> SET rank 50
OK
redis> INCRBY rank 20
(integer) 70
redis> GET rank
"70"
# key 不存在時
redis> EXISTS counter
(integer) 0
redis> INCRBY counter 30
(integer) 30
redis> GET counter
"30"
# key 不是數字值時
redis> SET book "long long ago..."
OK
redis> INCRBY book 200
(error) ERR value is not an integer or out of range
INCRBYFLOAT
格式:incrbyfloat key increment
為 key 中所儲存的值加上浮點數增量 increment 。
如果 key 不存在,那麼 INCRBYFLOAT 會先將 key 的值設為 0 ,再執行加法操作。
如果命令執行成功,那麼 key 的值會被更新為(執行加法之後的)新值,並且新值會
以字串的形式返回給呼叫者。
無論是 key 的值,還是增量 increment ,都可以使用像 2.0e7 、 3e5 、 90e-2 那
樣的指數符號(exponential notation)來表示,但是,執行 INCRBYFLOAT 命令之後的值總
是以同樣的形式儲存,也即是,它們總是由一個數字,一個(可選的)小數點和一個任意位
的小數部分組成(比如 3.14 、 69.768 ,諸如此類),小數部分尾隨的 0 會被移除,如果
有需要的話,還會將浮點數改為整數(比如 3.0 會被儲存成 3 )。
除此之外,無論加法計算所得的浮點數的實際精度有多長, INCRBYFLOAT 的計算結果
也最多隻能表示小數點的後十七位。
當以下任意一個條件發生時,返回一個錯誤:
 key 的值不是字串型別(因為 Redis 中的數字和浮點數都以字串的形式儲存,
所以它們都屬於字串型別)
 key 當前的值或者給定的增量 increment 不能解釋(parse)為雙精度浮點數
(double precision floating point number)
可用版本:
>= 2.6.0
時間複雜度:
O(1)
返回值:
執行命令之後 key 的值。
示例程式碼:
# 值和增量都不是指數符號
redis> SET mykey 10.50
OK
redis> INCRBYFLOAT mykey 0.1
"10.6"
# 值和增量都是指數符號
redis> SET mykey 314e-2
OK
redis> GET mykey # 用 SET 設定的值可以是指數符號
"314e-2"
redis> INCRBYFLOAT mykey 0 #但執行INCRBYFLOAT 之後格式會被改成非指數
符號
"3.14"
# 可以對整數型別執行
redis> SET mykey 3
OK
redis> INCRBYFLOAT mykey 1.1
"4.1"
# 後跟的 0 會被移除
redis> SET mykey 3.0
OK
redis> GET mykey # SET 設定的值小數部分
可以是 0
"3.0"
redis> INCRBYFLOAT mykey 1.000000000000000000000 # 但 INCRBYFLOAT
會將無用的 0 忽略掉,有需要的話,將浮點變為整數
"4"
redis> GET mykey
"4"
SETBIT
格式:setbit key offset value
對 key 所儲存的字串值,設定或清除指定偏移量上的位(bit)。
位的設定或清除取決於 value 引數,可以是 0 也可以是 1 。
當 key 不存在時,自動生成一個新的字串值。
字串會進行伸展(grown)以確保它可以將 value 儲存在指定的偏移量上。當字串值
進行伸展時,空白位置以 0 填充。
offset 引數必須大於或等於 0 ,小於 2^32 (bit 對映被限制在 512 MB 之內)。
警告:對使用大的 offset 的 SETBIT 操作來說,記憶體分配可能造成 Redis 伺服器被
阻塞。具體參考 SETRANGE 命令,warning(警告)部分。
可用版本:
>= 2.2.0
時間複雜度:
O(1)
返回值:
指定偏移量原來儲存的位。
示例程式碼:
redis> SETBIT bit 10086 1
(integer) 0
redis> GETBIT bit 10086
(integer) 1
redis> GETBIT bit 100 # bit 預設被初始化為 0
(integer) 0
GETBIT
格式:getbit key offset
對 key 所儲存的字串值,獲取指定偏移量上的位(bit)。
當 offset 比字串值的長度大,或者 key 不存在時,返回 0 。
可用版本:
>= 2.2.0
時間複雜度:
O(1)
返回值:
字串值指定偏移量上的位(bit)。
示例程式碼:
# 對不存在的 key 或者不存在的 offset 進行 GETBIT, 返回 0
redis> EXISTS bit
(integer) 0
redis> GETBIT bit 10086
(integer) 0
# 對已存在的 offset 進行 GETBIT
redis> SETBIT bit 10086 1
(integer) 0
redis> GETBIT bit 10086
(integer) 1
BITOP
格式:bitop operation destkey key [key ...]
對一個或多個儲存二進位制位的字串 key 進行位元操作,並將結果儲存到 destkey 上。
operation 可以是 AND 、 OR 、 NOT 、 XOR 這四種操作中的任意一種:
 BITOP AND destkey key [key ...] ,對一個或多個 key 求邏輯並,並將結果保
存到 destkey 。
 BITOP OR destkey key [key ...] ,對一個或多個 key 求邏輯或,並將結果儲存
到 destkey 。
 BITOP XOR destkey key [key ...] ,對一個或多個 key 求邏輯異或,並將結果
儲存到 destkey 。
 BITOP NOT destkey key ,對給定 key 求邏輯非,並將結果儲存到 destkey 。
除了 NOT 操作之外,其他操作都可以接受一個或多個 key 作為輸入。
處理不同長度的字串
當 BITOP 處理不同長度的字串時,較短的那個字串所缺少的部分會被看作 0 。
空的 key 也被看作是包含 0 的字串序列。
可用版本:
>= 2.6.0
時間複雜度:
O(N)
返回值:
儲存到 destkey 的字串的長度,和輸入 key 中最長的字串長度相等。
注:BITOP 的複雜度為 O(N) ,當處理大型矩陣(matrix)或者進行大資料量的統計時,
最好將任務指派到附屬節點(slave)進行,避免阻塞主節點。
示例程式碼:
redis> SETBIT bits-1 0 1 # bits-1 = 1001
(integer) 0
redis> SETBIT bits-1 3 1
(integer) 0
redis> SETBIT bits-2 0 1 # bits-2 = 1011
(integer) 0
redis> SETBIT bits-2 1 1
(integer) 0
redis> SETBIT bits-2 3 1
(integer) 0
redis> BITOP AND and-result bits-1 bits-2
(integer) 1
redis> GETBIT and-result 0 # and-result = 1001
(integer) 1
redis> GETBIT and-result 1
(integer) 0
redis> GETBIT and-result 2
(integer) 0
redis> GETBIT and-result 3
(integer) 1
BITCOUNT
格式:bitcount key [start] [end]
計算給定字串中,被設定為 1 的位元位的數量。
一般情況下,給定的整個字串都會被進行計數,通過指定額外的 start 或 end 引數,
可以讓計數只在特定的位上進行。
start 和 end 引數的設定和 GETRANGE 命令類似,都可以使用負數值:比如 -1 表示
最後一個位,而 -2 表示倒數第二個位,以此類推。
不存在的 key 被當成是空字串來處理,因此對一個不存在的 key 進行 BITCOUNT 操
作,結果為 0 。
可用版本:
>= 2.6.0
時間複雜度:
O(N)
返回值:
被設定為 1 的位的數量。
示例程式碼:
redis> BITCOUNT bits
(integer) 0
redis> SETBIT bits 0 1 # 0001
(integer) 0
redis> BITCOUNT bits
(integer) 1
redis> SETBIT bits 3 1 # 1001
(integer) 0
redis> BITCOUNT bits
(integer) 2
模式:使用 bitmap 實現使用者上線次數統計
Bitmap 對於一些特定型別的計算非常有效。
假設現在我們希望記錄自己網站上的使用者的上線頻率,比如說,計算使用者 A 上線了多
少天,使用者 B 上線了多少天,諸如此類,以此作為資料,從而決定讓哪些使用者參加 beta 測
試等活動 —— 這個模式可以使用 SETBIT 和 BITCOUNT 來實現。
比如說,每當使用者在某一天上線的時候,我們就使用 SETBIT ,以使用者名稱作為 key ,
將那天所代表的網站的上線日作為 offset 引數,並將這個 offset 上的為設定為 1 。
舉個例子,如果今天是網站上線的第 100 天,而使用者 peter 在今天閱覽過網站,那麼
執行命令 SETBIT peter 100 1 ;如果明天 peter 也繼續閱覽網站,那麼執行命令 SETBIT
peter 101 1 ,以此類推。
當要計算 peter 總共以來的上線次數時,就使用 BITCOUNT 命令:執行 BITCOUNT
peter ,得出的結果就是 peter 上線的總天數。
效能
前面的上線次數統計例子,即使執行 10 年,佔用的空間也只是每個使用者 10*365 位元
位(bit),也即是每個使用者 456 位元組。對於這種大小的資料來說, BITCOUNT 的處理速度就
像 GET 和 INCR 這種 O(1) 複雜度的操作一樣快。
如果你的 bitmap 資料非常大,那麼可以考慮使用以下兩種方法:
 將一個大的 bitmap 分散到不同的 key 中,作為小的 bitmap 來處理。使用 Lua
指令碼可以很方便地完成這一工作。
 使用 BITCOUNT 的 start 和 end 引數,每次只對所需的部分位進行計算,將位的
累積工作(accumulating)放到客戶端進行,並且對結果進行快取 (caching)。
Hash(雜湊表)
HSET
格式:hset key field value
將雜湊表 key 中的域 field 的值設為 value 。
如果 key 不存在,一個新的雜湊表被建立並進行 HSET 操作。
如果域 field 已經存在於雜湊表中,舊值將被覆蓋。
可用版本:
>= 2.0.0
時間複雜度:
O(1)
返回值:
如果 field 是雜湊表中的一個新建域,並且值設定成功,返回 1 。
如果雜湊表中域 field 已經存在且舊值已被新值覆蓋,返回 0 。
示例程式碼:
redis> HSET website google "www.g.cn" # 設定一個新域
(integer) 1
redis> HSET website google "www.google.com" # 覆蓋一箇舊域
(integer) 0
HSETNX
格式:hsetnx key field value
將雜湊表 key 中的域 field 的值設定為 value ,當且僅當域 field 不存在。
若域 field 已經存在,該操作無效。
如果 key 不存在,一個新雜湊表被建立並執行 HSETNX 命令。
可用版本:
>= 2.0.0
時間複雜度:
O(1)
返回值:
設定成功,返回 1 。
如果給定域已經存在且沒有操作被執行,返回 0 。
示例程式碼:
redis> HSETNX nosql key-value-store redis
(integer) 1
redis> HSETNX nosql key-value-store redis # 操作無效, 域
key-value-store 已存在
(integer) 0
HMSET
格式:hmset key field value [field value ...]
同時將多個 field-value (域-值)對設定到雜湊表 key 中。
此命令會覆蓋雜湊表中已存在的域。
如果 key 不存在,一個空雜湊表被建立並執行 HMSET 操作。
可用版本:
>= 2.0.0
時間複雜度:
O(N), N 為 field-value 對的數量。
返回值:
如果命令執行成功,返回 OK 。
當 key 不是雜湊表(hash)型別時,返回一個錯誤。
示例程式碼:
redis> HMSET website google www.google.com yahoo www.yahoo.com
OK
redis> HGET website google
"www.google.com"
redis> HGET website yahoo
"www.yahoo.com"
HGET
格式:hget key field
返回雜湊表 key 中給定域 field 的值。
可用版本:
>= 2.0.0
時間複雜度:
O(1)
返回值:
給定域的值。
當給定域不存在或是給定 key 不存在時,返回 nil 。
示例程式碼:
# 域存在
redis> HSET site redis redis.com
(integer) 1
redis> HGET site redis
"redis.com"
# 域不存在
redis> HGET site mysql
(nil)
HMGET
格式:hmget key field [field ...]
返回雜湊表 key 中,一個或多個給定域的值。
如果給定的域不存在於雜湊表,那麼返回一個 nil 值。
因為不存在的 key 被當作一個空雜湊表來處理,所以對一個不存在的 key 進行 HMGET
操作