在 《Redis 概述》 中咱們已經介紹過 DEL
、 EXISTS
、 EXPIRE
、SCAN
的用法了,下面咱們介紹其餘比較重要的命令。java
自1.0.0可用。python
時間複雜度:O(1)。redis
返回 key
所儲存的值的類型。shell
none
(key不存在)數據庫
string
(字符串)windows
list
(列表)緩存
set
(集合)網絡
zset
(有序集)數據結構
hash
(哈希表)架構
coderknock> OBJECT ENCODING zinterstoreTest "ziplist" coderknock> TYPE embstrKey string coderknock> TYPE setTest zset # 元素不存在 coderknock> TYPE nonKey none
自2.2.3可用。
時間複雜度:O(1)。
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
(爲了節約內存,Redis 會將字符串表示的 64 位有符號整數編碼爲整數來進行儲存)。
列表能夠被編碼爲 ziplist
或 linkedlist
或 quicklist
。 ziplist
是爲節約大小較小的列表空間而做的特殊表示。
集合能夠被編碼爲 intset
或者 hashtable
。 intset
是隻儲存數字的小集合的特殊表示。
哈希表能夠編碼爲 ziplist
或者 hashtable
。 ziplist
是小哈希表的特殊表示。
有序集合能夠被編碼爲 ziplist
或者 skiplist
格式。 ziplist
用於表示小的有序集合,而 skiplist
則用於表示任何大小的有序集合。
假如你作了什麼讓 Redis 沒辦法再使用節省空間的編碼時(好比將一個只有 1 個元素的集合擴展爲一個有 100 萬個元素的集合),特殊編碼類型(specially encoded types)會自動轉換成通用類型(general type)。
REFCOUNT
和 IDLETIME
返回數字。
ENCODING
返回相應的編碼類型。
若是您嘗試檢查的對象不存在,則返回 nil
。
coderknock> OBJECT IDLETIME nonKey (nil) coderknock> OBJECT IDLETIME embstrKey (integer) 2886 coderknock> OBJECT REFCOUNT embstrKey (integer) 1 coderknock> OBJECT REFCOUNT setTest (integer) 1 coderknock>
自1.0.0可用。
時間複雜度:O(1)。
將 key
更名爲 newkey
。
當 key
和 newkey
相同,或者 key
不存在時,返回一個錯誤。
當 newkey
已經存在時, RENAME
命令將覆蓋舊值。
更名成功時提示 OK
,失敗時候返回一個錯誤。
# 重命名不存在的 key coderknock> RENAME nonKey newNonKey (error) ERR no such key coderknock> RENAME setTest newSetTest OK coderknock> RENAME newSetTest newSetTest OK
爲了防止被強行 RENAME
,Redis 提供了 RENAMENX
命令,確保只有 newKey
不存在時候才被覆蓋。
自1.0.0可用。
時間複雜度:O(1)。
當且僅當 newkey
不存在時,將 key
更名爲 newkey
。
當 key
不存在時,返回一個錯誤。
修改爲功時,返回 1
。
若是 newkey
已經存在,返回 0
。
# 已經存在的就重命名不了了 coderknock> RENAMENX newSetTest newSetTest (integer) 0
在使用重命名命令時,有兩點須要注意:
因爲重命名鍵期間會執行 DEL
命令刪除舊的鍵,若是鍵對應的值比較大,會存在阻塞Redis的可能性,這點不要忽視。
若是 RENAME
和 RENAMENX
中的 key
和 newkey
若是是相同的,在 Redis3.2 和以前版本返回結果略有不一樣。
Redis3.2中會返回OK:
coderknock> rename key key OK
Redis3.2 以前的版本會提示錯誤:
coderknock> rename key key (error) ERR source and destination objects are the same
###隨機返回一個鍵
#### RANDOMKEY
自1.0.0可用。
時間複雜度:O(1)。
從當前數據庫中隨機返回(不刪除)一個 key
。值的類型。
當數據庫不爲空時,返回一個 key
。
當數據庫爲空時,返回 nil
。
coderknock> RANDOMKEY "ztest" coderknock> RANDOMKEY "testIntset" # 數據庫爲空 coderknock> FLUSHDB # 刪除當前數據庫全部 key OK coderknock> RANDOMKEY (nil)
Redis 鍵過時處理以前介紹的 EXPIRE
命令外還有 EXPIREAT
PEXPIRE
PEXPIREAT
PTTL
PERSIST
若是過時時間爲負值,鍵會當即被刪除,猶如使用 DEL
命令同樣。
對於字符串類型鍵,執行 SET
命令會去掉過時時間,這個問題很容易在開發中被忽視。
Redis 不支持二級數據結構(例如哈希、列表)內部元素的過時功能
SETEX
命令做爲 SET + EXPIRE
的組合,不可是原子執行,同時減小了一次網絡通信的時間#### EXPIREAT
自1.2.0可用。
時間複雜度:O(1)。
EXPIREAT
的做用和 *EXPIRE*
相似,都用於爲 key
設置生存時間。
不一樣在於 EXPIREAT
命令接受的時間參數是 UNIX 時間戳(unix timestamp)。
若是生存時間設置成功,返回 1
。
當 key
不存在或沒辦法設置生存時間,返回 0
。
coderknock> EXPIREAT test 1497338910 # 2017/6/13 15:28:30 過時 (integer) 1 coderknock> EXPIREAT nonkey 1497338910 (integer) 0
#### PEXPIRE
自2.6.0可用。
時間複雜度:O(1)。
這個命令和 EXPIRE
命令的做用相似,可是它以毫秒爲單位設置 key
的生存時間,而不像 EXPIRE
命令那樣,以秒爲單位。
設置成功,返回 1
key
不存在或設置失敗,返回 0
coderknock> SET test "coderknock" OK # 這裏設置的比較小須要一塊兒輸入這三個命令才能看出效果,或者時間設置的長些 coderknock> PEXPIRE test 1500 (integer) 1 coderknock> TTL test # TTL 的返回值以秒爲單位 (integer) 2 coderknock> PTTL test # PTTL 能夠給出準確的毫秒數 (integer) 1489
#### PEXPIREAT
自2.6.0可用。
時間複雜度:O(1)。
這個命令和 EXPIREAT
命令相似,但它以毫秒爲單位設置 key
的過時 unix 時間戳,而不是像 `EXPIREAT 那樣,以秒爲單位。
若是生存時間設置成功,返回 1
。
當 key
不存在或沒辦法設置生存時間時,返回 0
。(查看 EXPIRE
命令獲取更多信息)失敗,返回 0
coderknock> PEXPIREAT test 1497338910000 # 2017/6/13 15:28:30 過時 (integer) 1 coderknock> PEXPIREAT nonkey 1497338910000 (integer) 0
#### PTTL
自2.6.0可用。
時間複雜度:O(1)。
這個命令相似於 TTL
命令,但它以毫秒爲單位返回 key
的剩餘生存時間,而不是像 TTL
命令那樣,以秒爲單位。
當 key
不存在時,返回 -2
。
當 key
存在但沒有設置剩餘生存時間時,返回 -1
。
不然,以毫秒爲單位,返回 key
的剩餘生存時間。
在 Redis 2.8 之前,當 key
不存在,或者 key
沒有設置剩餘生存時間時,命令都返回 -1
。
# 不存在的 key coderknock> FLUSHDB OK coderknock> PTTL key (integer) -2 # key 存在,但沒有設置剩餘生存時間 coderknock> SET key value OK coderknock> PTTL key (integer) -1 # 有剩餘生存時間的 key coderknock> PEXPIRE key 10086 (integer) 1 coderknock> PTTL key (integer) 6179
#### PERSIST
自2.2.0可用。
時間複雜度:O(1)。
移除給定 key
的生存時間,將這個 key
從『易失的』(帶生存時間 key
)轉換成『持久的』(一個不帶生存時間、永不過時的 key
)。
當生存時間移除成功時,返回 1
.
若是 key
不存在或 key
沒有設置生存時間,返回 0
。
coderknock> SET test "coderknock" OK coderknock> EXPIRE test 1500 (integer) 1 coderknock> TTL test (integer) 1494 coderknock> PERSIST test # 移除 key 的生存時間 (integer) 1 coderknock> TTL test (integer) -1
遷移鍵功能很是重要,由於有時候咱們只想把部分數據由一個 Redis 遷移到另外一個 Redis(例如從生產環境遷移到測試環境),Redis 發展歷程中提供了 MOVE
、 DUMP + RESTORE
、MIGRATE
三組遷移鍵的方法,它們的實現方式以及使用的場景不太相同,下面分別介紹。
自1.0.0可用。
時間複雜度:O(1)。
將當前數據庫的 key
移動到給定的數據庫 db
當中。(Redis內部能夠有多個數據庫,彼此數據是相互隔離的)。
若是當前數據庫(源數據庫)和給定數據庫(目標數據庫)有相同名字的給定 key
,或者 key
不存在於當前數據庫,那麼 MOVE
沒有任何效果。
所以,也能夠利用這一特性,將 MOVE
看成鎖(locking)原語(primitive)。
移動成功返回 1
,失敗則返回 0
。
coderknock> SELECT 0 # 默認數據庫就是 0 ,這裏爲了讓你們更清晰 OK coderknock> GET test "a" coderknock> MOVE test 1 (integer) 1 coderknock> GET test # MOVE 後本庫的 test 鍵就被刪除了 (nil) coderknock> SELECT 1 OK coderknock[1]> GET test (nil) coderknock[1]> GET test "a" coderknock[1]> SET newTest db1 OK coderknock[1]> SELECT 0 coderknock> SET newTest db0 OK coderknock> MOVE newTest 1 # db 1 中有該鍵因此沒有遷移成功 (integer) 0 coderknock> GET newTest # db 0 中該鍵沒有刪除 "db0" coderknock> SELECT 1 OK coderknock[1]> GET newTest # db1 中 newTest也沒有變化 "db1"
### 遷移鍵 DUMP + RESTORE
#### DUMP
自2.6.0可用。
時間複雜度:查找給定鍵的複雜度爲 O(1) ,對鍵進行序列化的複雜度爲 O(N*M) ,其中 N 是構成
key
的 Redis 對象的數量,而 M 則是這些對象的平均大小。若是序列化的對象是比較小的字符串,那麼複雜度爲 O(1) 。
序列化給定 key
,並返回被序列化的值,使用 *RESTORE*
命令能夠將這個值反序列化爲 Redis 鍵。
序列化生成的值有如下幾個特色:
它帶有 64 位的校驗和,用於檢測錯誤, *RESTORE*
在進行反序列化以前會先檢查校驗和。
值的編碼格式和 RDB 文件保持一致。
RDB 版本會被編碼在序列化值當中,若是由於 Redis 的版本不一樣形成 RDB 格式不兼容,那麼 Redis 會拒絕對這個值進行反序列化操做。
序列化的值不包括任何生存時間信息。
若是 key
不存在,那麼返回 nil
。
不然,返回序列化以後的值。
coderknock> DUMP newSetTest "\x0c\"\"\x00\x00\x00\x1f\x00\x00\x00\x06\x00\x00\x03one\x05\xf2\x02\x03two\x05\xf3\x02\x05three\a\xf4\xff\a\x00\xde\xde\xc5\xd8|\x84\xd6\xd0"
#### RESTORE
自2.6.0可用。
時間複雜度:查找給定鍵的複雜度爲 O(1) ,對鍵進行反序列化的複雜度爲 O(N*M) ,其中 N 是構成
key
的 Redis 對象的數量,而 M 則是這些對象的平均大小。有序集合(sorted set)的反序列化複雜度爲 O(NMlog(N)) ,由於有序集合每次插入的複雜度爲 O(log(N)) 。
若是反序列化的對象是比較小的字符串,那麼複雜度爲 O(1) 。
反序列化給定的序列化值,並將它和給定的 key
關聯。
參數 ttl
以毫秒爲單位爲 key
設置生存時間;若是 ttl
爲 0
,那麼不設置生存時間。
RESTORE
在執行反序列化以前會先對序列化值的 RDB 版本和數據校驗和進行檢查,若是 RDB 版本不相同或者數據不完整的話,那麼 RESTORE
會拒絕進行反序列化,並返回一個錯誤。
若是鍵 key
已經存在, 而且給定了 REPLACE
選項, 那麼使用反序列化得出的值來代替鍵 key
原有的值; 相反地, 若是鍵 key
已經存在, 可是沒有給定 REPLACE
選項, 那麼命令返回一個錯誤。
更多信息能夠參考 *DUMP*
命令。
若是反序列化成功那麼返回 OK
,不然返回一個錯誤。
coderknock[1]> RESTORE restoreSet 0 "\x0c\"\"\x00\x00\x00\x1f\x00\x00\x00\x06\x00\x00\x03one\x05\xf2\x02\x03two\x05\xf3\x02\x05three\a\xf4\xff\a\x00\xde\xde\xc5\xd8|\x84\xd6\xd0" OK coderknock[1]> ZRANGE restoreSet 0 -1 1) "one" 2) "two" 3) "three" coderknock[1]> SELECT 0 coderknock> RESTORE restoreSet 0 "\x0c\"\"\x00\x00\x00\x1f\x00\x00\x00\x06\x00\x00\x03one\x05\xf2\x02\x03two\x05\xf3\x02\x05three\a\xf4\xff\a\x00\xde\xde\xc5\xd8|\x84\xd6\xd0" # 若是 key 已經存在但沒有設置 REPLACE 會 報錯 coderknock> RESTORE restoreSet 0 "\x0c\"\"\x00\x00\x00\x1f\x00\x00\x00\x06\x00\x00\x03one\x05\xf2\x02\x03two\x05\xf3\x02\x05three\a\xf4\xff\a\x00\xde\xde\xc5\xd8|\x84\xd6\xd0" (error) BUSYKEY Target key name already exists. coderknock> SADD restoreSet 1 java # 這裏修改下 restoreSet 中的值 coderknock> RESTORE restoreSet 0 "\x0c\"\"\x00\x00\x00\x1f\x00\x00\x00\x06\x00\x00\x03one\x05\xf2\x02\x03two\x05\xf3\x02\x05three\a\xf4\xff\a\x00\xde\xde\xc5\xd8|\x84\xd6\xd0" REPLACE OK coderknock> ZRANGE restoreSet 0 -1 1) "one" 2) "two" 3) "three" # 隨便輸一條序列化語句 coderknock> RESTORE test 0 "sui bian shu de" (error) ERR DUMP payload version or checksum are wrong
整個遷移過程並不是原子性的,而是經過客戶端分步完成的。
遷移過程是開啓了兩個客戶端鏈接,因此 DUMP
的結果不是在源 Redis 和目標 Redis 之間進行傳輸。
自2.6.0可用。
時間複雜度:這個命令在源實例上實際執行
*DUMP*
命令和*DEL*
命令,在目標實例執行*RESTORE*
命令,查看以上命令的文檔能夠看到詳細的複雜度說明。
key
數據在兩個實例之間傳輸的複雜度爲 O(N) 。
host
:目標Redis的IP地址 port
:目標Redis的端口 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
命令沒有關係)。
可選項:
COPY
:不移除源實例上的 key
。
REPLACE
:替換目標實例上已存在的 key
。
KEYS
- 若是key參數是一個空字符串,命令將會轉移 KEYS
選項後面的全部鍵(有關更多信息,請參閱上述部分)。
COPY
、REPLACE
僅在3.0及更高版本中可用。 KEYS
從 Redis 3.0.6 開始可用。
遷移成功時返回 OK
,不然返回相應的錯誤。
咱們須要再啓動一個 Redis 或者使用遠程 Redis(注意可訪問性)
redis-server --port 6370
咱們啓動兩個客戶端,一個鏈接默認 6379 的 Redis 一個鏈接 剛啓動的 6370 的Redis
redis-cli -p 6370 # 這裏只是列出了鏈接 6370 的方法
下面示例中注意端口的變化:
# 在 6379 中添加數據 coderknock: 6379> SADD 1 java 2 go 3 python (integer) 5 coderknock: 6379> SRANDMEMBER 1 "python" coderknock: 6379> keys * 1) "1" coderknock: 6379> flushdb OK coderknock: 6379> SADD set java python go (integer) 3 coderknock: 6379> SMEMBERS set 1) "python" 2) "java" 3) "go" coderknock: 6379> ZADD zSet 100coderknock 20 www.coderknock (integer) 2 coderknock: 6379> ZRANGE zSet 0 -1 1) "www.coderknock" 2) "coderknock" coderknock: 6379> SET hellocoderknock OK coderknock: 6379> KEYS * 1) "zSet" 2) "set" 3) "hello" # 在 6370 中添加數據 coderknock: 6370> SET db 6370 OK coderknock: 6370> SET set a b c (error) ERR syntax error coderknock: 6370> SADD set a b c (integer) 3 coderknock: 6370> KEYS * 1) "set" 2) "db" # 遷移一個 key coderknock: 6379> MIGRATE 127.0.0.1 6370 hello 0 1000 OK coderknock: 6379> GET hello # 當前的 Redis 中 hello 被刪除了 (nil) coderknock: 6370> GET hello # 6370 能夠查到 hello 這個 key 了 "CoderKnock" # 當使用 keys 參數時要求 key 必須是 空字符串(不能不設也不能設爲其餘) coderknock: 6379> MIGRATE 127.0.0.1 6370 0 1000 COPY KEYS "" (error) ERR When using MIGRATE KEYS option, the key argument must be set to the empty string coderknock: 6379> MIGRATE 127.0.0.1 6370 "zSet" 0 1000 COPY KEYS "" (error) ERR When using MIGRATE KEYS option, the key argument must be set to the empty string # 當輸入的 keys 都不存在時返回 NOKEY coderknock: 6379> MIGRATE 127.0.0.1 6370 "" 0 1000 COPY KEYS a NOKEY # 這裏不能使用通配符,通配符會當作普通字符處理 coderknock: 6379> MIGRATE 127.0.0.1 6370 "" 0 1000 COPY KEYS * NOKEY # 當目標庫有相同 key 會報錯 coderknock: 6379> MIGRATE 127.0.0.1 6370 "" 0 1000 COPY KEYS zSet set (error) ERR Target instance replied with error: BUSYKEY Target key name already exists. # 加入 REPLACE 參數正常 這裏 KEYS 須要在參數列表最後 否則會將 COPY 等當作是一個 key coderknock: 6379> MIGRATE 127.0.0.1 6370 "" 0 1000 COPY REPLACE KEYS zSet set OK # 使用了 COPY 因此當期庫中數據沒刪除 coderknock: 6379> KEYS * 1) "zSet" 2) "set" # 6370 中數據被遷移 coderknock: 6370> KEYS * 1) "set" 2) "hello" 3) "zSet" 4) "db" # set 的數據被替換 coderknock: 6370> SMEMBERS set 1) "java" 2) "go" 3) "python"
MIGRATE
命令也是用於在 Redis 實例間進行數據遷移的,實際上 MIGRATE
命令就是將DUMP
、RESTORE
、DEL
三個命令進行組合,從而簡化了操做流程。MIGRATE
命令具備原子性,並且從 Redis3.0.6 版本之後已經支持遷移多個鍵的功能,有效地提升了遷移效率。
《Redis 概覽》中的 KEYS
以及 SCAN
當須要遍歷全部鍵時(例如檢測過時或閒置時間、尋找大對象等), KEYS
是一個頗有幫助的命令,例如想刪除全部以 s
字符串開頭的鍵,能夠執行以下操做:
[coderknock ~]# redis-cli coderknock> set s1 a OK coderknock> set s2 b OK coderknock> set s3 c OK coderknock> set a a OK # 測試過程當中發現 windows 版本沒法這樣操做 [coderknock ~]# redis-cli keys s* | xargs redis-cli del (integer) 3
可是若是考慮到 Redis 的單線程架構就不那麼美妙了,若是 Redis 包含了大量的鍵,執行 KEYS
命令極可能會形成 Redis 阻塞,因此通常建議不要在生產環境下使用 KEYS
命令。但有時候確實有遍歷鍵的需求該怎麼辦,能夠在如下三種狀況使用:
在一個不對外提供服務的Redis從節點上執行,這樣不會阻塞到客戶端的請求,可是會影響到主從複製。
若是確認鍵值總數確實比較少,能夠執行該命令。
使用 SCAN
命令漸進式的遍歷全部鍵,能夠有效防止阻塞。
在 SCAN
的過程當中若是有鍵的變化(增長、刪除、修改),那麼遍歷效果可能會碰到以下問題:新增的鍵可能沒有遍歷到,遍歷出了重複的鍵等狀況,也就是說 SCAN
並不能保證完整的遍歷出來全部的鍵,這些是咱們在開發時須要考慮的。