一. 命令類型
? ? ? ? Redis中操作鍵的命令可以分為兩類。
- 一種命令可以對任意類型的鍵執行,比如說DEL,EXPIRE,RENAME,TYPE,OBJECT命令等。
舉個例子:
#字符串鍵
127.0.0.1:6379> set msg "hello world"
OK
#列表鍵
127.0.0.1:6379> rpush number 1 2 3
(integer) 3
#集合鍵
127.0.0.1:6379> sadd fruits apple banana cherry
(integer) 3
127.0.0.1:6379> keys *
1) "number"
2) "msg"
3) "fruits"
127.0.0.1:6379> del msg
(integer) 1
127.0.0.1:6379> del fruits
(integer) 1
127.0.0.1:6379> del number
(integer) 1
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379>
- 另一種命令是對特定類型的鍵執行?
1. SET, GET, APPEND,STRLEN等命令只能對字符串鍵使用。
2. HDEL, HSET, HGET,HLEN等命令只能對哈希鍵使用。
3. RPUSH, LPOP, LINSERT, LLEN等命令只能對列表鍵使用。
4. SADD, SPOP, SINTER, SCARD等命令只能對集合鍵使用。
5. ZADD, ZCARD, ZRANK, ZSCORE等命令只能對有序集合鍵使用。
例如:
? ? ? ? 對字符串鍵使用,只能對列表鍵使用的LLEN命令,redis返回了一個類型錯誤。
127.0.0.1:6379> set msg "hello world"
OK
127.0.0.1:6379> get msg
"hello world"
127.0.0.1:6379> llen msg
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379>
?二.類型檢測的實現
? ? ? ? 從上面的報錯可以看出,為了確保只有指定類型的鍵可以執行某些特殊命令,在執行一個類型特定的命令之前,Redis會先檢測輸入鍵的類型是否正確,然后再決定是否執行給定的命令。
? ? ? ? 類型特定命令所進行的類型檢查是通過redisObject結構中的type屬性來實現的。
? ? ? ? 流程圖如下:
三. 多態命令的實現
? ? ? ? Redis除了會根據值對象的類型判斷鍵是否能夠執行指定命令外,還會根據值對象的編碼方式,選擇正確的命令實現代碼來執行命令。
? ? ? ? 比如:列表對象的編碼可以是ziplist或者linkedlist,其中前者使用壓縮列表API實現列表命令,而后者則使用雙端鏈表API來實現列表命令。
? ? ? ? 假如,我們對一個鍵是喲個LLEN命令時,服務器除了需要確保執行命令的鍵是列表鍵,還需要根據鍵的編碼選擇正確的LLEN命令的實現:
- 如果是ziplist編碼,程序將使用ziplistlen函數返回列表長度。
- 如果是linkedlist編碼,程序將使用listlength函數返回雙端鏈表的長度。
? ? ? ? 借用面向對象的思想,我們可以認為LLEN命令是多態的,只需要執行LLEN命令的是列表鍵,不論是什么編碼,都會執行成功。
? ? ? ? 下圖展示了LLEN命令從類型檢查 到更具編碼來選擇實現函數的過程,其他類型特定命令的執行過程也類似:
? ? ? ? 實際上DEL, EXPIRE等命令也稱之為多態命令,無論使用的是什么類型,這些命令都可以執行成功。
? ? ? ? DEL, EXPIRE命令和LLEN命令的去表在于,前者是基于類型多態,后者是基于編碼多態。?