1. 安裝 Redis
docker pull redis:3.0-alpine
docker images
docker run --restart=always -d -p 6379:6379 -v /root/redis/data:/home/renzheng/redis/data xxx --requirepass "password"
docker exec -it xxx sh
2. 熱身
2.1 使用 redis-cli,并驗(yàn)證密碼:
renzheng@qingdao:~$ docker exec -it 813 sh
/data # redis-cli
127.0.0.1:6379> auth bP623f@dhNfb
OK
選擇數(shù)據(jù)庫 (Redis 命令不區(qū)分大小寫)
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK
2.2 獲得符合規(guī)則的 keys 列表
-
*:任意個(gè)字符 -
?:一個(gè)或多個(gè)字符 -
a[a-c]:aa、ab、ac
keys * 會(huì)遍歷 Redis 中所有鍵,如果鍵的數(shù)量較多則會(huì)影響性能,生產(chǎn)環(huán)境不建議使用
127.0.0.1:6379[1]> incr foo
(integer) 1
127.0.0.1:6379[1]> incr fool
(integer) 1
127.0.0.1:6379[1]> keys fo*
1) "foo"
2) "fool"
設(shè)值和取值:
127.0.0.1:6379[1]> set bar 1
OK
127.0.0.1:6379[1]> get bar
"1"
2.3 判斷一個(gè)鍵是否存在
存在返回整數(shù)類型 1,否則返回 0
127.0.0.1:6379[1]> exists bar
(integer) 1
2.4 刪除鍵
127.0.0.1:6379[1]> del bar
(integer) 1
Redis 中的 del 命令不支持批量刪除,但是我們可以憑借 Linux 的管道刪除多個(gè)鍵:
redis-cli keys "user*" | xargs redis-cli del
2.5 獲得鍵值的數(shù)據(jù)類型
type 命令用于獲取鍵值的數(shù)據(jù)類型,返回值可能是 string(字符串)、hash(散列)、list(列表)、set(集合類型)、zset(有序集合類型)。
127.0.0.1:6379[1]> set bar 1
OK
127.0.0.1:6379[1]> type bar
string
127.0.0.1:6379[1]> get bar
"1"
3. 字符串類型
字符串類型是 Redis 中最基本的數(shù)據(jù)類型,能夠存儲(chǔ)任何形式的字符串,包括二進(jìn)制數(shù)據(jù)。例如,可以存儲(chǔ)一個(gè)郵箱,JSON 序列化之后的對象,甚至是一張圖片。一個(gè)字符串類型鍵允許存儲(chǔ)的是數(shù)據(jù)最大容量是 512 MB。
3.1 命令
3.1.1 賦值和取值
SET key value
GET key
例如:
127.0.0.1:6379[1]> set greet "Hi!"
OK
127.0.0.1:6379[1]> get greet
"Hi!"
如果鍵不存在會(huì)返回空結(jié)果
127.0.0.1:6379[1]> get a
(nil)
3.1.2 遞增數(shù)字
INCR num
當(dāng)存儲(chǔ)的字符串是整數(shù)形式時(shí),Redis 提供了一個(gè) INCR 命令,可以讓當(dāng)前的鍵值遞增,并返回遞增后的值,如果鍵不存在會(huì)默認(rèn)賦值 0。例如:
127.0.0.1:6379[1]> incr foo
(integer) 1
127.0.0.1:6379[1]> incr foo
(integer) 2
127.0.0.1:6379[1]> type foo
string
127.0.0.1:6379[1]> get foo
"2"
如果鍵不是整數(shù),則出現(xiàn)如下錯(cuò)誤:
127.0.0.1:6379[1]> incr greet
(error) ERR value is not an integer or out of range
包括 INCR 在內(nèi)的所有 Redis 命令均為原子操作,不會(huì)出現(xiàn)并發(fā)沖突問題。
3.2 實(shí)踐
3.2.1 文章訪問量統(tǒng)計(jì)
每次訪問文章使用 INCR 命令使響應(yīng)的鍵值遞增。
鍵一般使用 object:id:property 的形式,例如:post:1:page.view
3.2.2 生成自增 id
每新增一個(gè)對象都使用 INCR 命令。
INCR user:count
3.2.3 存儲(chǔ)文章數(shù)據(jù)
對象序列化(JSON,MessagePack 等方式)。以存儲(chǔ) id 為 1的 文章為例:
set post:1:data str
3.3 其他命令
3.3.1 增加指定的整數(shù)
INCRBY 命令可以通過 increment 參數(shù)指定一次增加的數(shù)值
INCRBY key increment
127.0.0.1:6379[1]> set foo 100
OK
127.0.0.1:6379[1]> incrby foo 100
(integer) 200
127.0.0.1:6379[1]> get foo
"200"
3.3.2 減少指定的整數(shù)
DECR 命令與 INCR 命令用法相同,區(qū)別是讓數(shù)值減少。與 INCRBY 命令的相似的便是 DECRBY 命令。
3.3.3 增加指定的浮點(diǎn)數(shù)
INCRBYFLOAT 命令類似 INCR 命令,差別是可以增加一個(gè)雙精度浮點(diǎn)數(shù)。
INCRBYFLOAT key increment
例如:
127.0.0.1:6379[1]> set foo 1.000001
OK
127.0.0.1:6379[1]> incrbyfloat foo 0.000000003
"1.000001003"
3.3.4 向尾部追加值
APPEND 命令用來向鍵值末尾追加值。如果鍵不存在將該鍵的值設(shè)置為 value。
APPEND key value
例如:
127.0.0.1:6379[1]> set foo "Hello"
OK
127.0.0.1:6379[1]> append foo ", world!"
(integer) 13
127.0.0.1:6379[1]> get foo
"Hello, world!"
3.3.5 獲取字符串長度
STRLEN key
例如:
127.0.0.1:6379[1]> strlen foo
(integer) 13
3.3.6 同時(shí)獲得/設(shè)置多個(gè)鍵值
MSET/MGET 命令與 GET/SET 命令相似,只不過 MSET/MGET 可以設(shè)置/獲取多個(gè)鍵值。
MGET key [key ...]
MSET key value [key value ...]
例如:
127.0.0.1:6379[1]> mset foo 1 bar 2
OK
127.0.0.1:6379[1]> mget foo bar
1) "1"
2) "2"
3.3.7 位操作
GETBIT key offset (offset 從 0 開始)
SETBIT key offset value
BITCOUNT key
BITOP operation destkey key [key ...]
將 foo 設(shè)置為 "abc"(01100001 01100010 .. )
127.0.0.1:6379[1]> set foo abc
OK
獲取第 1、6 個(gè) bit
127.0.0.1:6379[1]> getbit foo 1
(integer) 1
127.0.0.1:6379[1]> getbit foo 6
(integer) 0
如果偏移量超出鍵值實(shí)際長度,則默認(rèn)為 0
127.0.0.1:6379[1]> getbit foo 30
(integer) 0
BITCOUNT 命令可以獲得字符串類型鍵中值為 1 的二進(jìn)制位個(gè)數(shù),例如:
127.0.0.1:6379[1]> bitcount foo
(integer) 10
可以通過參數(shù)限制統(tǒng)計(jì)的字節(jié)范圍,例如只統(tǒng)計(jì)前兩個(gè)字節(jié):
127.0.0.1:6379[1]> bitcount foo 0 1
(integer) 6
SETBIT 命令可以設(shè)置字符串類型鍵指定位置的二進(jìn)制位的值,返回值是該位置的舊值:
127.0.0.1:6379[1]> setbit foo 1 0
(integer) 1
127.0.0.1:6379[1]> get foo
"!bc"
如果設(shè)置一個(gè)不存在的鍵的指定二進(jìn)制位的值,會(huì)自動(dòng)將其前面的位賦值為 0:
127.0.0.1:6379[1]> setbit test 10 0
(integer) 0
127.0.0.1:6379[1]> get test
"\x00\x00"
如果指定的二進(jìn)制位超過了鍵值的實(shí)際長度,那么會(huì)自動(dòng)將中間的位全部設(shè)置為 0
127.0.0.1:6379[1]> setbit foo 31 0
(integer) 0
127.0.0.1:6379[1]> get foo
"!bc\x00"
BITOP 命令可以對多個(gè)字符串類型鍵進(jìn)行位運(yùn)算,并將結(jié)果存在 destkey 指定的鍵中。支持的運(yùn)算操作有 AND、OR、XOR、NOT。
127.0.0.1:6379[1]> set foo bar
OK
127.0.0.1:6379[1]> set foo aaa
OK
127.0.0.1:6379[1]> set bar bbb
OK
127.0.0.1:6379[1]> bitop or res foo bar
(integer) 3
127.0.0.1:6379[1]> get res
"ccc"
4. 散列(hash)類型
散列類型(hash)的鍵值也是一種字典結(jié)構(gòu),其存出了字段和字段值的映射,但是字段值只能是字符串,不支持其他數(shù)據(jù)類型。一個(gè)散列類型鍵至多包含 2^32 -1 個(gè)字段。
散列類型適合存儲(chǔ)對象,以 object:id 構(gòu)成鍵名,使用字段表示對象的屬性,自字段值則存儲(chǔ)屬性值,例如:
[圖片上傳失敗...(image-cf3390-1653622114110)]
散列類型不像關(guān)系型數(shù)據(jù)庫那樣要求所有的記錄都有同樣的屬性,而存在無法為單獨(dú)的某條記錄增加屬性的問題。Redis 完全可以自由地為任何鍵增減字段而不影響其他鍵。
4.1 常用命令
4.1.1 取值與賦值
HSET key field value
HGET key field
HMSET key field value [field value ...]]
HMGET key field [field ...]
HGETALL key
例如:
127.0.0.1:6379[1]> hset car color red (不存在該字段則建立該字段,返回 1;存在則更新,返回 0)
(integer) 1
127.0.0.1:6379[1]> hset car name "BMW"
(integer) 1
127.0.0.1:6379[1]> hset car price "500000"
(integer) 1
127.0.0.1:6379[1]> hmget car color name price
1) "red"
2) "BMW"
3) "500000"
127.0.0.1:6379[1]> hgetall car
1) "color"
2) "red"
3) "name"
4) "BMW"
5) "price"
6) "500000"
127.0.0.1:6379[1]> type car
hash
4.1.2 判斷字段是否存在
HEXISTS key field
例如:
127.0.0.1:6379[1]> hexists car color
(integer) 1 (存在返回 1,不存在返回 0)
4.1.3 當(dāng)字段不存在時(shí)賦值
HSETNX key field value
HSETINX 命令與 HSET 命令相似,只不過 HSETNX 只有字段不存在時(shí)才賦值,字段如果存在則不執(zhí)行任何操作。
127.0.0.1:6379[1]> hsetnx person age 1
(integer) 0 // 存在返回 0
127.0.0.1:6379[1]> hget person age
"20"
127.0.0.1:6379[1]> hsetnx person height 165
(integer) 1 // 字段不存在,設(shè)值,且返回 1
4.1.4 增加數(shù)字
HINCRBY key field increment
HINCRBY 命令與 INCRBY 命令相似,如果字段不存在。Hash 類型沒有類似 INCR 的命令,不過可以通過執(zhí)行 HINCRBY key field 1 來實(shí)現(xiàn)。如果鍵或者字段不存在,那么將自動(dòng)創(chuàng)建鍵和字段,并賦值為 increment。
例:
127.0.0.1:6379[1]> hincrby car price 1
(integer) 500001
127.0.0.1:6379[1]> hincrby person age 20
(integer) 20
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"
4.1.5 刪除字段
hdel key field
例:
127.0.0.1:6379[1]> hset person name "Renzheng"
(integer) 1
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"
3) "name"
4) "Renzheng"
127.0.0.1:6379[1]> hdel person name
(integer) 1
127.0.0.1:6379[1]> hgetall person
1) "age"
2) "20"
4.2 實(shí)踐
4.2.1 存儲(chǔ)文章數(shù)據(jù)
[圖片上傳失敗...(image-43c2a3-1653622114110)]
4.2.2 存儲(chǔ)文章縮略名
使用一個(gè)的 slug.to.id hash 類型鍵用于存儲(chǔ)文章縮略名和文章 ID 的對應(yīng)關(guān)系。
如果需要發(fā)布文章,偽代碼如下:
// 獲取文章 ID
$postId = INCR posts:count
// 判斷文章縮略名 slug 是否可用,如果不可用則賦值
$isSlugAvailable = HSETNX slug.to.id $slug $postId
// 縮略名存在
if $isSlugAvailable = 0
exit
HMSET post:$postId title $title content $content slug $slug
4.3 其他命令
4.3.1 只獲取字段名或字段值
127.0.0.1:6379[1]> hkeys car
1) "color"
2) "name"
3) "price"
127.0.0.1:6379[1]> hvals car
1) "red"
2) "BMW"
3) "500001"
4.3.2 獲得字段數(shù)量
127.0.0.1:6379[1]> hlen car
(integer) 3
5. 列表(list)類型
List 類型可以存儲(chǔ)一個(gè)有序的字符串列表,常用的操作是向列表兩端添加元素,或者獲得列表的某一個(gè)片段。list 類型內(nèi)部由雙向鏈表實(shí)現(xiàn),所以向列表兩端添加元素的時(shí)間復(fù)雜度為 O(1),獲取越接近兩端的元素越快,代價(jià)是通過索引訪問元素比較慢。
場景:新鮮事(插入最新,獲取最新)、日志。
借助 list 類型,Redis 還可以作為隊(duì)列使用。
一個(gè) list 類型鍵最多容納 2^32 - 1 個(gè)元素。
5.1 常用命令
5.1.1 向列表兩端添加元素
LPUSH key value [value ...]
RPUSH key value [value ...]
LPUSH 命令用來向列表左邊添加元素,返回值為添加元素后列表的長度。
例如:
127.0.0.1:6379[1]> lpush nums 1
(integer) 1
127.0.0.1:6379[1]> lpush nums 2 3
(integer) 3
按照以上命令,nums 中元素變化如下:
[]
[1]
[3, 2, 1]
5.1.2 從列表兩端彈出元素
LPOP key
RPOP key
LPOP 命令可以從列表左邊彈出一個(gè)元素。該命令執(zhí)行兩個(gè)操作:
- 將列表左邊的元素從列表中移除
- 返回被移除的元素
例如:
127.0.0.1:6379[1]> lpop nums
"3"
5.1.3 獲取列表中元素的個(gè)數(shù)
LLEN key
如果 key 不存在,LLEN 命令返回 0。例如:
127.0.0.1:6379[1]> llen nums
(integer) 2
127.0.0.1:6379[1]> llen foo // foo 不存在
(integer) 0
LLEN 命令的功能類似于關(guān)系型數(shù)據(jù)庫中的 select count(*) from table_name,但是 LLEN 的時(shí)間復(fù)雜度為 O(1),使用時(shí)會(huì)直接讀取現(xiàn)成的值,并不需要遍歷一遍獲得數(shù)據(jù)。
5.1.4 獲得列表片段
LRANGE key start stop
LRANGE 可以獲得列表中的一個(gè)片段,返回索引從 start 到 stop 之間的元素(索引從 0 開始,包括 stop 元素)。
例如:
127.0.0.1:6379[1]> lrange nums 0 1
1) "2"
2) "1"
LRANGE 命令也支持負(fù)索引,表示從右邊開始計(jì)算,如 -1 表示從最右邊第一個(gè)元素開始,-2 表示最右邊第二個(gè)元素,依此類推。
127.0.0.1:6379[1]> lrange nums -2 -1
1) "2"
2) "1"
如果 stop 大于實(shí)際的索引范圍,則會(huì)返回到列表中最右邊的元素。
5.1.5 刪除列表中指定的值
LREM key count value
LREM 命令將刪除前 count 個(gè)值為 value 的元素,返回實(shí)際刪除的元素。
例如:
127.0.0.1:6379[1]> lpush nums 1 0 1 0 1 0 1 0 1 0
(integer) 10
127.0.0.1:6379[1]> lrange nums 0 -1
1) "0"
2) "1"
3) "0"
4) "1"
5) "0"
6) "1"
7) "0"
8) "1"
9) "0"
10) "1"
127.0.0.1:6379[1]> lrem nums 3 1
(integer) 3
127.0.0.1:6379[1]> lrange nums 0 -1
1) "0"
2) "0"
3) "0"
4) "0"
5) "1"
6) "0"
7) "1"
根據(jù) count 值的不同,LREM 命令的執(zhí)行方式會(huì)略有差異:
count > 0時(shí),LREM命令會(huì)從左邊刪除前count個(gè)值為value的元素;count < 0時(shí),LREM命令會(huì)刪除從右邊開始刪除前|count|個(gè)值為value的元素;count = 0時(shí),LREM命令將刪除所有值為value的元素。
5.2 實(shí)踐
5.2.1 存儲(chǔ)文章 ID 列表
使用鍵 posts:list 記錄文章 ID 列表。當(dāng)發(fā)布新文章時(shí),使用 LPUSH 命令把文章的 ID 加入至這個(gè)列表中,刪除文章時(shí)將列表中的文章 ID 刪除??梢允褂?LRANGE 命令實(shí)現(xiàn)文章分頁列表,偽代碼如下:
$postPerPage = 10
$start = ($currentPage - 1) * $postsPerPage
$end = $currentPage * $postsPerPage - 1
$postIds = LRANGE posts:list $start $end
# 循環(huán)獲取文章信息
for $id in $postIds
print HGET post:$id title
5.2.2 存儲(chǔ)文章評論
將文章評論序列化之后,使用字符串的形式將評論存入形如 posts:id:comments 的列表中。
偽代碼如下:
$serializedComment = serialize($author, $email, $time, $content)
LPUSH post:1:comments $serializedComment
讀取時(shí),依然使用 LRANGE 命令。
5.3 其他命令
5.3.1 獲得/設(shè)置指定索引的元素值
LINDEX key index
LSET KEY index value
LINDEX 用來返回指定索引的元素,索引從 0 開始。
例如:
127.0.0.1:6379[1]> lrange nums 0 -1
1) "0"
2) "9"
3) "8"
4) "7"
5) "6"
6) "5"
7) "4"
8) "3"
9) "2"
10) "1"
127.0.0.1:6379[1]> lindex nums 0
"0"
127.0.0.1:6379[1]> lindex nums 2
"8"
LSET 命令將索引為 index 的元素設(shè)置為 value,例如:
127.0.0.1:6379[1]> lset nums 0 99999
OK
127.0.0.1:6379[1]> lrange nums 0 -1
1) "99999"
2) "9"
3) "8"
4) "7"
5) "6"
6) "5"
7) "4"
8) "3"
9) "2"
10) "1"
5.3.2 只保留列表指定片段
LTRIM key start end
LTRIM 命令可以刪除指定索引范圍之外的所有元素,其指定的列表范圍的方法和 LRANGE 命令相同。
例如:
127.0.0.1:6379[1]> lrange nums 0 -1
1) "99999"
2) "9"
3) "8"
4) "7"
5) "6"
6) "5"
7) "4"
8) "3"
9) "2"
10) "1"
127.0.0.1:6379[1]> ltrim nums 1 -1
OK
127.0.0.1:6379[1]> lrange nums 0 -1
1) "9"
2) "8"
3) "7"
4) "6"
5) "5"
6) "4"
7) "3"
8) "2"
9) "1"
5.3.3 向列表中插入元素
LINSERT key BEFORE|AFTER pivot value
LINSERT 命令在列表中從左到右查找值為 pivot 的元素,然后根據(jù)第二個(gè)參數(shù)是 BEFORE 還是 AFTER 決定將 value 插入到該元素的前面還是后面。LINSERT 命令的返回值為插入后列表元素的個(gè)數(shù)。
例如:
127.0.0.1:6379[1]> lrange nums 0 -1
1) "1"
2) "9"
3) "8"
4) "7"
5) "6"
6) "5"
7) "4"
8) "3"
9) "2"
10) "1"
127.0.0.1:6379[1]> linsert nums before 1 0
(integer) 11
127.0.0.1:6379[1]> lrange nums 0 -1
1) "0"
2) "1"
3) "9"
4) "8"
5) "7"
6) "6"
7) "5"
8) "4"
9) "3"
10) "2"
11) "1"
5.3.4 將元素從一個(gè)列表轉(zhuǎn)移至另一個(gè)列表
RPOPLPUSH src des
RPOPLPUSH 命令會(huì)先從 src 列表的右邊彈出一個(gè)元素,然后將其加入至 des 列表的左邊,并返回這個(gè)元素的值。整個(gè)過程是原子的。
6. 集合(set)類型
在集合中每個(gè)元素都是不同的,而且沒有順序。一個(gè) set 類型的鍵可以至多存儲(chǔ) 2^32 - 1 個(gè)字符串。
[圖片上傳失敗...(image-e0c4ba-1653622114110)]
集合類型在 Redis 內(nèi)部是使用值為空的 Hash Table 實(shí)現(xiàn)的。
6.1 常用命令
6.1.1 增加/刪除元素
SADD key member [member ...]
SREM key [member] [member ...]
SADD 命令用于向集合中添加一個(gè)元素或多個(gè)元素,如果鍵不存在則自動(dòng)創(chuàng)建,元素已存在則忽略。返回值為成功加入元素的數(shù)量。
例如:
127.0.0.1:6379[1]> sadd foo a
(integer) 1
127.0.0.1:6379[1]> sadd foo a b c
(integer) 2
SREM 命令用于從集合中刪除一個(gè)或者多個(gè)元素,返回成功刪除的個(gè)數(shù)。
例如:
127.0.0.1:6379[1]> srem foo a d
(integer) 1
6.1.2 獲得集合中所有元素
SMEMBERS key
SMEMBERS 命令從集合中返回所有元素。例如:
127.0.0.1:6379[1]> del foo
(integer) 1
127.0.0.1:6379[1]> sadd foo a b c
(integer) 3
127.0.0.1:6379[1]> smembers foo
1) "c"
2) "b"
3) "a"
6.1.3 判斷元素是否存在于集合中
SISMEMBER key member
時(shí)間復(fù)雜度為 O(1),SISMEMBER 當(dāng)值存在時(shí)返回 1,當(dāng)值不存在或者鍵不存在時(shí)返回 0。例如:
127.0.0.1:6379[1]> sismember foo a
(integer) 1
127.0.0.1:6379[1]> sismember foo d
(integer) 0
6.1.4 集合運(yùn)算
SDIFF key [key ...]
SINTER key [key ...]
SUNION key [key ...]
-
SDIFF用來對集合之間執(zhí)行差集運(yùn)算。127.0.0.1:6379[1]> sadd aset a b c (integer) 3 127.0.0.1:6379[1]> sadd bset b c d (integer) 3 127.0.0.1:6379[1]> sdiff aset bset 1) "a" 127.0.0.1:6379[1]> smembers aset 1) "c" 2) "b" 3) "a" -
SINTER用來對多個(gè)集合執(zhí)行交集運(yùn)算。127.0.0.1:6379[1]> sinter aset bset 1) "c" 2) "b" -
SUNION用來對多個(gè)集合執(zhí)行并集運(yùn)算。127.0.0.1:6379[1]> sunion aset bset 1) "c" 2) "b" 3) "d" 4) "a"
6.2 實(shí)踐
6.2.1 存儲(chǔ)文章標(biāo)簽
一篇文章的各個(gè)標(biāo)簽均是不同的,而且展示時(shí)對這些標(biāo)簽的順序沒有要求,可以使用 set 類型鍵存儲(chǔ)文章標(biāo)簽。對每篇文章使用形如 posts:id:tags 的鍵存儲(chǔ)該篇文章的標(biāo)簽。
偽代碼如下:
SADD post:1:tags Java Spring MyBatis
SREM post:1:tags MyBatis
// 顯示所有標(biāo)簽
$tags = SMEMBERS post:1:tags
6.2.2 通過標(biāo)簽查詢文章
使用形如 tag:標(biāo)簽:posts 的 set 類型鍵存儲(chǔ)每個(gè)標(biāo)簽對應(yīng)標(biāo)簽。
6.3 其他命令
6.3.1 獲取集合中元素的個(gè)數(shù)
SCARD key
SCARD 命令用于獲取集合中元素的個(gè)數(shù),例如:
127.0.0.1:6379[1]> scard aset
(integer) 3
6.3.2 進(jìn)行集合運(yùn)算并將結(jié)果存儲(chǔ)
SDIFFSTORE des key [key ...]
SINTERSTORE des key [key ...]
SUNIONSTORE des key [key ...]
不直接返回運(yùn)算結(jié)果,而將結(jié)果存儲(chǔ)在 des 鍵中。
127.0.0.1:6379[1]> sdiffstore cset aset bset
(integer) 1
127.0.0.1:6379[1]> smembers cset
1) "a"
6.3.3 隨機(jī)獲取集合中的元素
SRANDMEMBER key [count]
SRANDMEMBER 命令用于隨機(jī)從集合中獲取一個(gè)元素,例如:
127.0.0.1:6379[1]> srandmember aset
"b"
也可以傳遞一個(gè) count 參數(shù)一次獲得多個(gè)元素,而根據(jù) count 參數(shù)的正負(fù)不同返回結(jié)果略有差異:
- 當(dāng)
count為正數(shù)時(shí),SRANDMEMBER命令將從集合中隨機(jī)獲得count個(gè)不重復(fù)的元素; - 當(dāng)
count為負(fù)數(shù)時(shí),SRANDMEMBER命令將從集合中隨機(jī)獲得可能相同的|count|個(gè)元素。
6.3.4 從集合中彈出一個(gè)元素
SPOP key
由于集合是無序的,因此 SPOP 命令會(huì)從集合中隨機(jī)選擇一個(gè)元素彈出。例如:
127.0.0.1:6379[1]> spop aset
"a"
127.0.0.1:6379[1]> smembers aset
1) "c"
2) "b"
7. 有序集合
有序集合(sorted set) 類型在 set 類型的基礎(chǔ)上為集合中的每個(gè)元素都關(guān)聯(lián)了一個(gè)分?jǐn)?shù),這使得我們不僅可以完成插入、刪除、判斷是否存在等 set 類型支持的操作,還能進(jìn)行獲得分?jǐn)?shù)最高(最低)的前 N 個(gè)元素、獲得指定分?jǐn)?shù)范圍內(nèi)的元素等與分?jǐn)?shù)相關(guān)的操作。
雖然集合中每個(gè)元素都不相同,但是分?jǐn)?shù)可以相同。
7.1 命令
7.1.1 增加元素
ZADD key score member [score member]
ZADD 命令用于向 sorted set 中添加一個(gè)或多個(gè)元素及他們的分?jǐn)?shù),如果該元素已經(jīng)存在,那么則會(huì)用新的分?jǐn)?shù)替代舊的分?jǐn)?shù)。ZADD 命令的返回值為新加入集合中的元素個(gè)數(shù)。例如:
127.0.0.1:6379[1]> zadd scoreboard 98 Tom 87 Mike 94 Mary
(integer) 3
127.0.0.1:6379[1]> zadd scoreboard 86.5 Mike
(integer) 0
127.0.0.1:6379[1]> zadd scoreboard +inf Mike // 設(shè)置分?jǐn)?shù)為正無窮
(integer) 0
127.0.0.1:6379[1]> zadd scoreboard -inf Mike // 設(shè)置分?jǐn)?shù)為負(fù)無窮
(integer) 0
7.1.2 獲得元素的分?jǐn)?shù)
ZSCORE key member
例如:
127.0.0.1:6379[1]> zscore scoreboard Mike
"86.5"
7.1.3 獲得在某個(gè)排名范圍內(nèi)的元素列表
ZRANGE key start stop [withscores]
ZREVRANGE key start stop [withscores]
ZRANGE 命令會(huì)按照元素的分?jǐn)?shù)從小到大排序返回索引從 start 到 stop 之間的所有元素(包括兩端),索引方式與 LRANGE 命令相同。ZREVRANGE 命令按照分?jǐn)?shù)從大到小排序。
127.0.0.1:6379[1]> zrange scoreboard 0 2
1) "Mike"
2) "Mary"
3) "Tom"
127.0.0.1:6379[1]> zrange scoreboard 0 2 withscores
1) "Mike"
2) "86.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"
127.0.0.1:6379[1]> zrevrange scoreboard 0 2 withscores
1) "Tom"
2) "98"
3) "Mary"
4) "94"
5) "Mike"
6) "86.5"
如果兩個(gè)元素的分?jǐn)?shù)相同,則按照字典順序排序。
7.1.4 獲取指定分?jǐn)?shù)范圍內(nèi)的元素
ZRANGEBYSCORE key min max [withscore] [limit offset count]
ZRANGEBYSCORE 命令按照元素分?jǐn)?shù)從小到大的順序返回分?jǐn)?shù)在 min 和 max 之間的元素,例如:
127.0.0.1:6379[1]> zrangebyscore scoreboard 80 90
1) "Mike"
如果希望分?jǐn)?shù)不包括端點(diǎn)值,則可以在分?jǐn)?shù)前加上 (,例如:
127.0.0.1:6379[1]> zrangebyscore scoreboard 80 86.5
(empty list or set)
min 和 max 還支持無窮大,類似于 ZADD 命令,-inf 和 +inf 分別表示負(fù)無窮和正無窮。例如:
127.0.0.1:6379[1]> zrangebyscore scoreboard (80 +inf withscores
1) "Mike"
2) "88.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"
limit offset count 表示在獲得列表的基礎(chǔ)上,向后偏移 offset 個(gè)元素,并只獲取前 count 個(gè)元素。例如:
// 獲取高于 60 分并從第 2 個(gè)人開始的 3 個(gè)人
127.0.0.1:6379[1]> zrangebyscore scoreboard (60 +inf withscores limit 1 3
1) "Mary"
2) "94"
3) "Tom"
4) "98"
ZREVRANGEBYSCORE 命令命令不僅按照元素分?jǐn)?shù)從大到小排序,而且該命令的 min 和 max 參數(shù)順序和 ZRANGEBYSCORE 命令是相反的。
7.1.5 增加某個(gè)元素的分?jǐn)?shù)
ZINCRBY key increment member
ZINCRBY 命令可以增加某個(gè)元素的分?jǐn)?shù),返回值為更改之后的分?jǐn)?shù)。例如:
127.0.0.1:6379[1]> zincrby scoreboard 2 Mike
"88.5"
127.0.0.1:6379[1]> zrange scoreboard 0 -1 withscores
1) "Mike"
2) "88.5"
3) "Mary"
4) "94"
5) "Tom"
6) "98"
7.2 實(shí)踐
7.2.1 實(shí)現(xiàn)文章按照訪問量排序
使用鍵名 posts:page.view 的鍵記錄每篇文章的 ID 和訪問量,每次訪客訪問一篇文章,則通過 ZINCRBY posts:page.view 1 postId 更新訪問量。偽代碼如下:
$postsPerpage = 10
$start = $(currentPage - 1) * $postsPerPage
$end = $currentPage * $postsPerPage - 1;
$postIds = ZREVRANGE posts:page.view $start $end
foreach $id in $postIds
$title = HGET post:$id title
7.2.2 改進(jìn)按照時(shí)間排序
同樣采用有序集合,記錄文章 ID 和 Unix 時(shí)間
7.3 其他命令
7.3.1 獲得集合中元素的數(shù)量
ZCARD key
例如:
127.0.0.1:6379[1]> zcard scoreboard
(integer) 3
7.3.2 獲得指定分?jǐn)?shù)范圍內(nèi)元素個(gè)數(shù)
ZCOUNT key min max
例如:
127.0.0.1:6379[1]> zcount scoreboard 80 90
(integer) 1
7.3.3 刪除一個(gè)或多個(gè)元素
ZREM key member
ZREM 返回值是成功刪除元素的數(shù)量
127.0.0.1:6379[1]> zrem scoreboard Mike
(integer) 1
127.0.0.1:6379[1]> zrange scoreboard 0 -1
(empty list or set)
7.3.4 按照排名范圍刪除元素
ZREMRANGEBYRANK key start stop
ZREMRANGEBYRANK 命令按照元素從?。ㄗ钚?0)到大排序刪除排名在指定范圍內(nèi)的所有元素,并返回刪除元素的數(shù)量。例如:
127.0.0.1:6379[1]> zremrangebyrank scoreboard 1 3
(integer) 2
127.0.0.1:6379[1]> zrange scoreboard 0 -1
1) "Mike"
7.3.5 按照分?jǐn)?shù)范圍刪除元素
ZREMRANGEBYSCORE key min max
ZREMRANGEBYSOCRE 會(huì)刪除指定分?jǐn)?shù)范圍內(nèi)所有的元素,參數(shù) min 和 max 的特性和 ZRANGEBYSCORE 命令中的一樣。返回值是刪除元素的數(shù)量。
7.3.6 獲得元素的排名
ZRANK key member
ZREVRANK key member
ZRANK 命令會(huì)按照元素分?jǐn)?shù)從小到大的順序獲得指定的元素排名,從0 開始。而 ZREVRANK 命令則相反,分?jǐn)?shù)最大的元素排名為 0。
7.3.6 計(jì)算有序集合的交集
ZINTERSTORE des numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
ZINTERSTORE 命令用來計(jì)算多個(gè)有序集合的交集,并將結(jié)果存儲(chǔ)在 des 鍵中(同樣以有序集合類型存儲(chǔ)),返回值為 des 鍵中的元素個(gè)數(shù)。
des 鍵中元素的分?jǐn)?shù)由 AGGREGATE 參數(shù)決定:
- 當(dāng)
AGGREGATE參數(shù)是SUM(默認(rèn))時(shí),des鍵中的元素分?jǐn)?shù)是每個(gè)參與計(jì)算集合中該元素分?jǐn)?shù)的和; - 當(dāng)
AGGREGATE參數(shù)是MIN(默認(rèn))時(shí),des鍵中的元素分?jǐn)?shù)是每個(gè)參與計(jì)算集合中該元素分?jǐn)?shù)的最小值; - 當(dāng)
AGGREGATE參數(shù)是MAX (默認(rèn))時(shí),des` 鍵中的元素分?jǐn)?shù)是每個(gè)參與計(jì)算集合中該元素分?jǐn)?shù)的最大值;
ZINTERSTORE 命令還能通過 WEIGHTS 參數(shù)設(shè)置每個(gè)集合的權(quán)重,每個(gè)集合在參與計(jì)算時(shí)元素的分?jǐn)?shù)會(huì)被乘上該集合的權(quán)重。
另外還有一個(gè)命令 ZUNIONSTORE 計(jì)算集合并集,用法與 ZINTERSTORE 命令相同。