1. 程式人生 > >Redis-型別檢查與命令多型

Redis-型別檢查與命令多型


8.7 型別檢查與命令多型
Redis中用於操作鍵的命令基本上可以分為兩種型別。
其中一種命令可以對任何型別的鍵執行,比如說DEL命令、EXPIRE命令、RENAME命令、TYPE命令、OBJECT命令等。
舉個例子,以下程式碼就展示了使用DEL命令來刪除三種不同型別的鍵:
#字串鍵
redis> SET msg "hello"
OK
#列表鍵
redis> RPUSH numbers 1 2 3
(integer) 3
#集合鍵
redis> SADD fruits apple banana cherry
(integer) 3
redis> DEL msg
(integer) 1
redis> DEL numbers
(integer) 1
redis> DEL fruits
(integer) 1
而另一種命令只能對特定型別的鍵執行,比如說:
❑SET、GET、APPEND、STRLEN等命令只能對字串鍵執行;
❑HDEL、HSET、HGET、HLEN等命令只能對雜湊鍵執行;
❑RPUSH、LPOP、LINSERT、LLEN等命令只能對列表鍵執行;
❑SADD、SPOP、SINTER、SCARD等命令只能對集合鍵執行;
❑ZADD、ZCARD、ZRANK、ZSCORE等命令只能對有序集合鍵執行;
舉個例子,我們可以用SET命令建立一個字串鍵,然後用GET命令和APPEND命令操作這個鍵,但如果我們試圖對這個字串鍵執行只有列表鍵才能執行的LLEN命令,那麼Redis將向我們返回一個型別錯誤:
redis> SET msg "hello world"
OK
redis> GET msg
"hello world"
redis> APPEND msg " again!"

(integer) 18
redis> GET msg
"hello world again!"
redis> LLEN msg
(error) WRONGTYPE Operation against a key holding the wrong kind of value
8.7.1 型別檢查的實現
從上面發生型別錯誤的程式碼示例可以看出,為了確保只有指定型別的鍵可以執行某些特定的命令,在執行一個型別特定的命令之前,Redis會先檢查輸入鍵的型別是否正確,然後再決定是否執行給定的命令。
型別特定命令所進行的型別檢查是通過redisObject結構的type屬性來實現的:
❑在執行一個型別特定命令之前,伺服器會先檢查輸入資料庫鍵的值物件是否為執行命令所需的型別,如果是的話,伺服器就對鍵執行指定的命令;
❑否則,伺服器將拒絕執行命令,並向客戶端返回一個型別錯誤。
舉個例子,對於LLEN命令來說:
❑在執行LLEN命令之前,伺服器會先檢查輸入資料庫鍵的值物件是否為列表型別,也即是,檢查值物件redisObject結構type屬性的值是否為REDIS_LIST,如果是的話,伺服器就對鍵執行LLEN命令;
❑否則的話,伺服器就拒絕執行命令並向客戶端返回一個型別錯誤;圖8-18展示了這一型別檢查過程。

圖8-18 LLEN命令執行時的型別檢查過程
其他型別特定命令的型別檢查過程也和這裡展示的LLEN命令的型別檢查過程類似。
8.7.2 多型命令的實現
Redis除了會根據值物件的型別來判斷鍵是否能夠執行指定命令之外,還會根據值物件的編碼方式,選擇正確的命令實現程式碼來執行命令。
舉個例子,在前面介紹列表物件的編碼時我們說過,列表物件有ziplist和linkedlist兩種編碼可用,其中前者使用壓縮列表API來實現列表命令,而後者則使用雙端連結串列API來實現列表命令。
現在,考慮這樣一個情況,如果我們對一個鍵執行LLEN命令,那麼伺服器除了要確保執行命令的是列表鍵之外,還需要根據鍵的值物件所使用的編碼來選擇正確的LLEN命令實現:
❑如果列表物件的編碼為ziplist,那麼說明列表物件的實現為壓縮列表,程式將使用ziplistLen函式來返回列表的長度;
❑如果列表物件的編碼為linkedlist,那麼說明列表物件的實現為雙端連結串列,程式將使用listLength函式來返回雙端連結串列的長度;
借用面向物件方面的術語來說,我們可以認為LLEN命令是多型(polymorphism)的,只要執行LLEN命令的是列表鍵,那麼無論值物件使用的是ziplist編碼還是linkedlist編碼,命令都可以正常執行。
圖8-19展示了LLEN命令從型別檢查到根據編碼選擇實現函式的整個執行過程,其他型別特定命令的執行過程也是類似的。
實際上,我們可以將DEL、EXPIRE、TYPE等命令也稱為多型命令,因為無論輸入的鍵是什麼型別,這些命令都可以正確地執行。

DEL、EXPIRE等命令和LLEN等命令的區別在於,前者是基於型別的多型——一個命令可以同時用於處理多種不同型別的鍵,而後者是基於編碼的多型——一個命令可以同時用於處理多種不同編碼。