String
字符串類型是redis的最基本類型,首先無論值是什么數據類型,其鍵都是字符串,且其他數據類型的數據結構都是在字符串的基礎上搭建的,相信讀者能夠體會到字符串在redis的地位是有多么的重要。
那么字符串的值可以是什么呢?
- 簡單的字符串,復雜的字符串如JSON,XML的格式的字符串都是可以的。
- 數字(整數、浮點數)
- 二進制如音頻、圖片的
當然值的大小不是無限的,不然的話你買內存的錢就可以買整個宇宙了。redis規定其值最大不能大過512M。
操作String
-
往redis種插入字符串類型的值
set key value
-
根據鍵獲取值
get key
-
查看字符串長度
strlen key
-
批量設置值
mset key value [key value]
-
批量取值
mget key [key]
批量操作的命令可有效地提高開發命令,但mget、mset的時間復雜度是O(n),因此一次設置的鍵值對多的話,可能會引起redis服務器的阻塞。
-
如果字符串類型的值是數字,自增命令(每次加1)
incr key
-
指定每次加的值
incrby key amount
-
如果字符串類型的值是數字,自減命令(每次減1)
decr key
-
往字符串里面追加字符串 (類似JAVA中StringBuilder的append)
append key value
-
根據開始索引和結束索引獲取字符串的部分
getrange key start_index end_index
-
根據索引設定指定位置的值
setrange key index value
-
設置后,其他命令不能夠修改該鍵值,直到鍵刪除或者時間到了后釋放(redis官方給出了使用setnx實現分步鎖的方式)
set key value nx ex 10
-
為鍵設置秒級過期時間/毫秒級過期時間
setex/setpx key 10 value
String的內部編碼
字符串類型的內部編碼有三種類型:
- int 8個字節的長整型
- embstr 小於等於32字節的字符串
- raw 大於32字節
redis的底層數據結構類似JAVA中的ArrayList類型,都是有着預分配冗余空間,防止反復的空間擴展降低效率,redis中規定如果當前的字符串大小小於1M時擴容都是當前大小的加倍,而如果字符串的大小大於1M的時候,無論大於多少只會擴容1M,而前面說到redis規定值的大小只有512M。
List
List類型是用來存儲多個有序字符串的,List中的每個元素稱為元素,可以往左push添加元素,也可以往右push元素,當然也可以獲取指定范圍的元素,還可以按照自己的需求獲取List中指定的元素。一個列表中最多可以存儲2^23-1個元素,它底層其實是一個雙向的鏈表,對兩端的性能很高,而通過索引下標操作中間的節點時性能會較差。
List有如下兩個特點:
- List中的元素都是有序的,因此我們能夠根據索引或者起始位置加終止位置獲取我們想要的值。
- List中的元素是能夠重復。
操作List
-
往左插入元素
lpush key value [value]
-
往右插入元素
rpush key value [value]
-
往值位置的前面或者后面加入元素
linsert key BEFORE|AFTER value new_value
-
根據起始索引和終止索引查看范圍的值
lrange key start_index end_index
-
根據值在列表中的索引查找值
lindex key index
-
獲取列表的長度
lren key
-
彈出列表左邊的元素
lpop key
-
彈出列表右邊的元素
rpop key
-
刪除指定元素
lrem key count value
-
裁剪列表
ltrim key start_index end_index
-
修改特定的值
lset key index value
-
阻塞式向右彈出
brpop key
-
阻塞式向左彈出
blpop key
List內部編碼
列表類型的內部編碼有兩種。
- ziplist:當列表的值元素個數小於list-max-ziplist-entries(默認是512個),且每個元素的值小於64自己時,redis采用ziplist的形式存儲列表,減少了內存的使用。
- linkedlist:當列表其值不滿足ziplist的條件的時候,redis會采用鏈表的形式存儲值。
但在redis3.2版本之后(筆者采用的是redis6.2.5),當元素大於512個或元素大小超過64個字節,內部編碼已從linkedlist變為quicklist。
quicklist采用了ziplist的優點和linkedlist的優點,也就是每個節點都是一個ziplist節點之間用雙向的指針聯系起來,這樣即使得內存使用的減少滿足了快速的插入和刪除,也減少了空間的冗余。
Set
Set類型也是用來存儲多個元素的,但是集合內的元素是無序的,而且它不允許有重復的元素出現在同一個鍵中,類似JAVA中的Set集合。這些特性促使了用戶在操作集合時沒有辦法通過索引去查找元素,也沒有辦法去獲取一個范圍之內的值。與List一樣,redis規定一個集合類型中最多可以存儲2^23-1個元素,同時集合還支持交集、並集、差集,功能頗多。
操作Set
-
往集合中插入元素
sadd key value [value]
-
刪除集合中的元素
srem key value
-
查詢一個集合中的元素的個數
scard key
-
判斷一個元素於一個集合中存在與否
sismember key value
-
隨機在集合中獲取想要個數的元素(默認是一個)
srandmember key [count]
-
隨機在集合中彈出想要個數的元素(默認是一個)
spop key [count]
-
查詢一個集合中所有的元素
smembers key
-
對兩個集合做交集計算
sinter first_key second_key
-
對兩個集合做並集計算
sunion first_key second_key
-
對兩個集合做差集計算
sdiff first_key second_key
-
將兩個集合交\並\差集的計算結果存入另一個鍵中
sinterstore store_key first_key second_key sunionstore store_key first_key second_key sdiffstore store_key first_key second_key
Set的內部編碼
- intset:當集合中的元素都是整數且元素的個數不超過set-max-intset-entries(512)時,redis內部用intset來實現集合,目的還是為了減少內存的使用。
- hashtable:當集合內部的元素類型、個數不滿足intset的要求的話,redis將用hsahtable來實現集合的內部。就如JAVA中的HashSet一樣其內部使用HashMap來實現的,只不過是多個值對一個鍵,hashtable和其一樣,內部都是用HashMap來實現的,也是多個值對一個鍵。
Hash
Hash可以是哈希,字典,也可以是關聯數組。在redis中,哈希類型指值是一個鍵值對結構,這有點套娃,不知道為什么筆者總感覺其值很像JSON對象。哈希類型中的映射關系叫作field-value,這里的value是指值中field對應的值,可不敢是鍵的值。筆者認為Hash特點適合去存儲對象,當然String類型也可以去存儲對象的信息,但是你說一個人的特征拆成塊,放到大海中,需要的時候去尋找,你就不怕男變女嗎? Hash中鍵可以存儲多個field-value,每個field不能相同,field與value映射,這就很好地把一個對象兜起來了。
操作Hash
-
插入數據
hset key field value [field value]
-
根據field取出值
hget key field
-
批量插入數據
hmset key field value [key field value]
-
根據field批量取出數據
hmget key field [field]
-
根據field刪除數據
hdel key field [field]
-
查看哈希類型所有的field
hkeys key
-
查看哈希類型所有的value
hvals key
-
判斷field是否存在
hexists key field
-
獲取哈希所有的field-value
hgetall key
Hash內部編碼
- ziplist: 當哈希類型元素小於hash-max-ziplist-entries(默認512個),且其大小小於hash-max-ziplist-value(62字節)時,redis內部采用ziplist形式對其編碼,目的是為了減少內存的使用,為什么?因為內存很貴啊。
- hashtable: 當哈希類型元素不滿足ziplist的條件時,redis內部使用hashtable的形式對其編碼。hashtable就像JAVA中的HashSet一樣,底層都是用HashMap實現的,特點是一個鍵對多個值,我想哈希類型的field-value十分像Map<String,Object>,可能其底層是Map<String,Map<String,Object>>,很套娃很喜歡。
Zset
Zset與Set相似,一樣是集合,集合中的元素不能夠相同,但是不同的是有序集合的每一個元素都有自己的分數,所以有序集合可以根據分數來進行排序,這也說明我們能夠以索引/分數的方式獲取到一個或者一個范圍中的值。在實際的開發中,有序集合給我們提供了分數查詢,范圍查詢,事物排行榜的功能。
盡管有序集合中,元素不能夠相同,但是各元素的分數是能夠相同的!拜托!你是你我是我,又不是抄你試卷,為什么分數不能一樣呢?
操作Zset
-
往有序集合中添加元素
zadd key score value [score value]
-
刪除有序集合中的元素
zrem key value
-
計算有序集合中元素的個數
zcard key
-
計算某個元素的分數
zscore key value
-
查詢某個元素的排名
zrank key value zrevrank key value//倒序排名
-
獲取指定排名的元素
zrange key start end zrange key start end withscores zrevrange key start end zrevrange key start end withscores
有序集合是按照分數的高低來排名的,所以zrange命令獲取的是一份從低到高的排行榜,zrevrange反之,而后面帶着withscores命令的,在展示排行榜的時候會帶上每一個元素的分數。
-
為指定元素增加指定分數
zincrby key value score
-
根據分數的范圍獲取指定范圍的元素
zrangebyscore key min max [withscores] zrevrangebyscore key max min [withscores]
其中min、max支持開區間,閉區間,而-inf和+inf分別代表無窮小和無窮大。
示例:
-
有序集合的交\並\差集計算
zinterstore store_key num_key actual_key [actual_key] zunionstore store_key num_key actual_key [actual_key] zdiffstore store_key num_key actual_key [actual_key]
此計算與集合的計算一致,多了個num_key,其實就是你要計算的鍵的數量,相較於集合來說便是一次可計算多個鍵。
Zset內部編碼
- ziplist: 當有序集合中的元素個數不超過zset-max-ziplist-entires(512),且每個元素的大小不超過zset-max-ziplist-value時,zset在redis的內部編碼是ziplist,減少內存的使用。
- skiplist: 當有序集合里的元素不滿足ziplist的條件時,zset在redis的內部編碼是shiplist,俗稱跳躍表。
所謂的跳躍表便是不循環地遍歷每個節點,而是跳躍形式地搜查,如果搜查到的節點比要找的節點要小的話便繼續跳躍搜查,如果要大的話,便轉換到下一層的搜查,直到找到為止,這比ziplist的查找減少了次數,提高了查找的效率。