WBG被JDG淘汰官博炸鍋!Theshy選劍魔被質疑眾解說發文感嘆,369採訪誅心了
語法
首先,Redis 是 key - Value 鍵值對記憶體資料庫,它使用五種基本資料型別來儲存 Value 資料,下面我們分別來介紹。
String 字串
String 型別就是字串型別,它是二進位制安全的,也就是說字串是以二進位制流進行處理,不會對其進行其餘的操作,比方說轉義字元,"\" 在其餘環境下可能就是一個 "" ,但是在 Redis 中它就是 "\",String 型別的值最多能夠儲存 512 MB 的資料,接下來我們簡單看一下,如何在 Redis 中儲存和查詢一個字串值:
儲存: set、mset、setex、psetex、setnx 和 msetnx 命令
// set String_Key String_Value: 設定一個字串型別的 Redis 鍵值對 // setnx String_Key String_Value: 如果指定的鍵不存在就設定一個字串型別的 Redis 鍵值對 set stringkey stringvalue // set 命令一次只能設定一個 Key-Value 對,而 mset 可以同時設定多個 Key-Value 對 // mset Key_1 Value_1 [Key_2 Value_2] [...]:同時設定多個字串型別的 Redis 鍵值對 // msetnx Key_1 Value_1 [Key_2 Value_2] [...]:同時設定多個字串型別的 Redis 鍵值對,但是一旦出現重複全部不生效 mset key1 value1 key2 value2 key3 value3 // setex String_Key seconds String_Value :設定 String 型別的 Redis 鍵值對,但是在 seconds 秒後此鍵失效 setex key1 5 value1 // 5 秒後 key1 失效 // psetex String_Key mills String_Value :設定 String 型別的 Redis 鍵值對,但是在 mills 毫秒後此鍵失效 psetex key2 1000 value2 // 1000 毫秒後 key2 失效
查詢: get、getrange、gitbit、mget 和 strlen 命令
// get String_Key :獲取指定 Redis 鍵的字串值
get stringkey
執行結果: "stringvalue"
// getrange String_Key start end :獲取指定 Redis 鍵的字串值中指定索引區間 [start, end] 中的字元集合
getrange stringkey 0 -6
執行結果:"string"
為什麼是 "string" 呢?那是因為 Redis 索引設定的問題,對於一個字串,它這樣規定:
順序索引: 0 1 2 3 5 6 7 8 9 10 11 逆序索引: -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 字串值: s t r i n g v a l u e
可以看出規定順序索引是從 0 開始的,而一個負數索引,比如 -6 指的是從右往左(逆序)數過來的第六位字元,所以 [0, -6] 表示從左邊第一位開始到逆序數來的第六位為止,這個概念很重要,後面會重複利用到,也會再簡單重複一次。
// getbit String_Key offset:獲取指定 Redis 鍵的字串值的二進位制流中偏移開頭第一位的二進位制位
getbit stringkey 6 // 執行結果:(integer) 1
這個 1 是怎麼來的呢?因為 gitbit 是獲取二進位制流中的偏移二進位制位,所以我們需要寫出 stringkey 對應值 stringvalue 的二進位制流,這裡因為只偏移 6 ,而 s 的 ascii 碼為 115 ,對應二進位制編碼為 : 01110011,而偏移 6 位就是第 7 位的二進位制值,也就是 1,故得 1。
// 同理,get 只能查一個 Redis 鍵值對,而 mget 可以查多個
// mget String_Key1 [String_Key2] [...] : 獲取多個指定 Redis 鍵的字串值
mget key1 key2 key3
執行結果: 1) "value1"
2) "value2"
3) "value3"
// strlen String_Key :獲取指定 Redis 鍵的字串值的長度,也就是由多少個字元組成
strlen stringkey // 執行結果:(integer) 11
修改:getset、incr、incrby、incrbyfloat、decr、decrby 、append 和 setbit 命令
// getset String_Key String_Value :設定新值並返回舊值
getset stringkey string_value_new // 執行結果:"stringvalue"
// incr stringkey :將指定 Redis 鍵的字串值加一,如果可以的話。返回修改後的值
// decr stringkey :將指定 Redis 鍵的字串值減一,如果可以的話。返回修改後的值
setex test 60 1
incr test // 執行結果:"2"
decr test // 執行結果:"1"
// incrby / incrbyfloat stringkey increment : 將指定 Redis 鍵的字串值加 increment,如果可以的話。
// 前者要為整數字符串,後者為浮點數字符串,返回修改後的值
// decrby stringkey increment : 將指定 Redis 鍵的字串值減 increment,如果可以的話。
// 值要為整數字符串,返回修改後的值
setex test 60 1
incr test 3 // 執行結果:(integer) 4
decr test 3 // 執行結果:(integer) 1
// append String_Key String_Value : 在指定 Redis 鍵的字串值後追加 String_Value,返回追加後的字串長度
append stringkey _append // 執行結果:(integer) 19
// setbit String_Key offset value:設定指定 Redis 鍵的字串值的二進位制流中
// 偏移開頭第一位的二進位制位為 value(0 或 1),成功返回 1
在開始之前,我們先分析一波,stringkey 鍵的值現在是 string_value_append ,由前面的討論可知,s 的二進位制編碼是 01110011,我們先看看執行結果:
setbit stringkey 6 0 // 執行結果:(integer) 1
get stringkey // 執行結果:"qtring_value_append"
為什麼 s 會變成 q 呢?因為 01110011 偏移 6 位,就是第七位,然後將它改為 0,也就是變成了這樣:
順序索引: 0 1 2 3 5 6 7 8
原二進位制: 0 1 1 1 0 0 1 1 // 115 ASCII碼錶示為 s
今二進位制: 0 1 1 1 0 0 0 1 // 113 ASCII碼錶示為 q
故原字串的 s 變為了 q。
刪除:del 命令
// del Key :直接刪除 Redis 中的一個 Key-Value 鍵值對,它不僅可以用以刪除 String 型別
del stringkey
Hash 雜湊
Hash 也是 Redis 的一種值型別,而且 Hash 型別不似 String 型別,它是一個集合,最多可有 2^32 - 1 個元素,每個元素又是一個鍵值對。接下來介紹一下如何在 Redis 中簡單儲存和獲取一個 Hash 型別的值:
儲存: hset 和 hmset 命令
// hset Key Value_key Value_value : Key 是 Redis Key-Value 中的 Key,而 Value_key Value_value 則是 Value 集合中的一個元素
hset book bookId_1 bookName_Java
// 同理 hset 只能設定 Value 集合中的一個元素,hmset 則可同時設定多個 Value 集合元素
// hmset Key Value_key1 Value_value1 [Value_key2 Value_value2] [...]
hmset book bookId_1 bookName_Java bookId_2 bookName_C bookId_3 bookName_Python
查詢:hget 、hmget、hgetall 、hexists、hlen、hkeys 和 hvals命令
// 獲取指定 Key 的 Hash 集合中的指定鍵的值
hget book bookId_1
執行結果:"bookName_Java"
// hmget Hash_Key value_key1 [value_key2] [...] :查詢集合中的指定元素(通過鍵指定)
hmget book bookId_1 bookId_2 bookId_3
執行結果:
1) "bookName_Java"
2) "bookName_C"
3) "bookName_Python"
// 獲取指定 Key 的 Hash 集合中的所有鍵值對資訊
hgetall book
執行結果: 1) "bookId_1"
2) "bookName_Java"
3) "bookId_2"
4) "bookName_C"
5) "bookId_3"
6) "bookName_Python"
// hexists Hash_Key value_key1: 鍵值對集合中是否存在指定鍵的元素,返回匹配的元素總數
hexists book bookId_1
執行結果:(integer) 1
// hlen Hash_Key :返回鍵值對集合的元素總數
hlen book
執行結果:(integer) 3
// hkeys Hash_Key :獲取鍵值對集合中所有元素的鍵
hkeys book
執行結果:
1) "bookId_1"
2) "bookId_2"
3) "bookId_3"
// hvals Hash_Key :獲取鍵值對集合中所有元素的值
hvals book
執行結果:
1) "bookName_Java"
2) "bookName_C"
3) "bookName_Python"
修改:當要修改 Value 集合中的某個已存在的元素的鍵值對中的值時,可以重新儲存覆蓋原值。
// hincrby Hash_Key value_key increment: 如果鍵值對集合中的指定元素的值是整型資料,
// 那麼可以使用此命令使其鍵增減 increment,返回修改後的數值
// hincrbyfloat Hash_Key value_key increment: 如果鍵值對集合中的指定元素的值是浮點型資料,
// 那麼可以使用此命令使其鍵增減 increment,返回修改後的數值
// 示例:
hmset test int 1 float 2.0
hincreby test int 5 // 執行結果:(integer) 6
hincrbyfloat test float 8 // 執行結果:"10"
刪除:當要刪除 Value 集合中的元素時,可以使用 hdel 命令同時刪除一個或者多個元素:
// hdel Key Value_key1 [Value_key2] [...]
hdel book bookId_1 bookId_2
List 列表
List 型別也是一個集合型別,但是它允許集合中有多個相同的元素(所以嚴格來說它並不是集合,故而稱其為列表),而 Hash 型別雖也是集合型別,但其每個元素的鍵都不允許重複,List 型別集合中的元素也並非鍵值對,而是單值的,元素數量最多為 2^32 - 1 個,同時允許以佇列的形式來操作集合列表。接下來了解一下如何儲存和獲取一個 List 型別的值:
儲存:lpush 、 rpush 和 linsert 命令
// 在集合列表左邊,也就是佇列頭部前面順序新增一個或多個元素
// lpush Key value_1 [value_2] [...]
lpush queue 1 2 3
列表結果: 3 2 1
// 在集合列表右邊,也就是佇列尾部後面順序新增一個或多個元素
// rpush Key value_1 [value_2] [...]
rpush queue 1 2 3
列表結果:3 2 1 1 2 3
// 在指定的元素(通過值匹配而非索引)前或後插入一個元素,
// 若有多個匹配以從左到右匹配到的第一個元素為準
// linsert List_Key (before| after) pivot value
linsert queue after 2 100
列表結果:3 2 100 1 1 2 3
查詢:lrange 和 lindex 命令
// 可以先用 llen 命令瞭解佇列長度
// llen Key
llen queue
執行結果:(integer) 7
// 按照從左到右的順序遍歷佇列來查詢所有元素或者在指定區間 [start, stop] 內的所有元素
// 當 stop = -1 時表示遍歷列表所有元素,注意 start 和 stop 都是指索引 index
// lrange Key start stop
lrange queue 0 -1
執行結果: 1) "3"
2) "2"
3) "100"
4) "1"
5) "1"
6) "2"
7) "3"
// 使用 lindex 命令可以檢視列表中指定位置索引的元素值,等效於 queue[index]
// 注意 index 是從 0 開始計數的,而不是如上面的執行結果一般從 1 開始
// lindex List_Key index
lindex queue 3
執行結果:"1"
對於索引,Redis 有其自己的設定,除了大家所熟知的從前往後遞增的從 0 開始的索引,還有從後往前遞減的從 -1 開始的索引,暫且稱其為逆序索引,所謂 -1 表示的是從後往前數列表中第一個元素,大概就是這樣:
數值索引: 0 1 2 3 4 5
逆序索引: -6 -5 -4 -3 -2 -1
元素集合: 3 2 1 1 2 3
所以 lrange queue 0 -1,之所以可以遍歷整個佇列是因為:索引 0 表示開始元素是佇列第一個元素,索引 -1 表示結束元素是佇列從後往前數的第一個元素,也就是最後一個元素,如此便把整個佇列都包含進了佇列裡。
修改: lset 命令
// lset 用來修改列表中指定索引的元素值
// lset List_Key index value
lset queue 3 1000
列表結果:3 2 100 1000 1 2 3
刪除:lpop、rpop、lrem 和 ltrim 命令
// lpop List_Key :返回列表最左邊的元素,即隊頭元素
lpop queue
執行結果:"3"
列表結果:2 100 1000 1 2 3
// rpop List_Key :返回列表最右邊的元素,即隊尾元素
rpop queue
執行結果:"3"
列表結果:2 100 1000 1 2
// lrem List_Key count value:移除指定數量(通過 count 指定)的指定元素(通過 value 匹配)
// count > 0 時從左往右匹配 |count| 個元素; count < 0 時從右往左匹配 |count| 個元素; count = 0 時匹配所有元素
// 返回移除的元素數量
lrem queue -1 1
執行結果:(integer) 1
列表結果:2 100 1000 2
// 又如
lrem queue -2 2
執行結果:(integer) 2
列表結果:100 1000
// ltrim key start stop :不在 [start, stop] 區間內的所有元素都刪除, start < stop 時無動作
ltrim queue 0 1
列表結果:100 1000
Set 集合
List 型別允許集合中有重複的值,但是 Set 型別卻不允許有重複的值,正如集合自身的定義,元素無序而唯一,元素數量同樣地,不超過 2^32 - 1 個。下面簡單介紹一下在 Redis 中如何儲存和查詢一個 Set 型別的值:
儲存:sadd 命令
// sadd Set_Key value1 [value2] [...] :往一個 Set 型別集合中新增一個或多個唯一元素,
// 返回新增成功的元素數量
sadd myset 1 2 3
執行結果:(integer) 3
查詢:scard 、smembers、sismember 和 srandmember 命令
// scard Set_key:獲取集合元素總數
scard myset
執行結果:(integer) 3
// smembers Set_Key:獲取集合中的所有元素
smembers myset
執行結果: 1) "1"
2) "2"
3) "3"
// sismember Set_Key value:詢問某個值是不是集合中的元素,返回值 0 表示不是
sismember myset 5
執行結果:(integer) 0
// srandmember Set_Key [count]:count 可選的,預設為 1,從集合中返回 count 個隨機元素
srandmember myset 2
執行結果(多次執行結果會不一樣): 1) "2"
2) "1"
刪除:spop 、srem 和 smove 命令
// spop Set_Key : 移除集合中的一個隨機元素並返回
spop myset
執行結果:"2"
// srem Set_key value1 [value2] [...]:移除集合中一個或多個指定元素,返回移除成功的元素個數
srem myset 2 3
執行結果:(integer) 1
// smove Set_Key_1 Set_Key_2 value : 將 Set_Key_1 集合中指定的元素(value)剪下到 Set_Key_2 集合中
// 返回剪下成功的元素個數,0 為剪下失敗
smove myset yourset 2
執行結果:(integer) 0
集合的專屬特殊操作:交、並、差運算
// 建立兩個 Set 型別的集合
sadd myset 1 2 3
sadd yourset 1 5 6
// 並運算: myset 並 yourset
// sunion Set_Key_1 [Set_Key_2] [...] :返回多個集合的並集
// sunionstore destination_Set_Key Set_Key_1 [Set_Key_2] [...] :
// 將多個集合的並集結果儲存到 destination_Set_Key 中,並返回並集元素總數
sunion myset yourset
執行結果:
1) "1"
2) "2"
3) "3"
4) "5"
5) "6"
// 交運算: myset 交 yourset
// sinter Set_Key_1 [Set_Key_2] [...] :返回多個集合的交集
// sinterstore destination_Set_Key Set_Key_1 [Set_Key_2] [...] :
// 將多個集合的並集結果儲存到 destination_Set_Key 中,並返回交集元素總數
sinter myset yourset
執行結果:
1) "1"
// 差運算: myset - yourset
// sdiff Set_Key_1 [Set_Key_2] [...] :返回第一個集合與其他集合的差集,
// 即將第一個集合後的所有集合先並起來,再與第一個集合進行差運算或者順序做差運算
// sdiffstore destination_Set_Key Set_Key_1 [Set_Key_2] [...] :
// 將第一個集合與其他集合的差集結果儲存到 destination_Set_Key 中,並返回差集元素總數
sdiff myset yourset
執行結果:
1) "2"
2) "3"
Zset 有序集合
相比 Set 型別,它們的區別在於元素是否有序,Zset 型別的集合元素是有序的,而 Set 型別的集合元素是無序的,那它是如何確保有序的呢?答每個元素在新增時給它綁定了一個雙浮點型的分數,集合中的元素就按照這個分數進行排序。同樣的,我們來看一下在 Redis 中如何儲存或者查詢一個 Zset 型別:
儲存: zadd 命令
// zadd ZSet_Key score1 value1 [score2 value2] [...] : 往一個 Zset 集合中新增一個或多個帶有分數的元素,
// 返回加入成功的元素個數
zadd myzset 1.0 one 2.0 two 3.0 three 3.0 three1 3.0 three2 3.0 three3
執行結果:(integer) 6
查詢:zcard、zcount、zlexcount、zrange、zrevrange、zrangebylex、zrangebyscore、zrevrangebyscore、zrank、zrevrank 和 zscore 命令
// zcard ZSet_Key: 返回集合元素總數
zcard myzset
執行結果:(integer) 6
// zcount ZSet_Key minscore maxscore : 返回分數在區間 [minscore, maxscore] 中的元素總數
zcount myzset 0.5 2
執行結果:(integer) 2
在這裡要特別的講一下,lex 是什麼,它被譯為字典,也就是在元素分數不一致時,按照分數順序排,而分數一樣時,按照字典順序排,所謂字典順序就比如 a-z, A-Z。
// zlexcount ZSet_Key min max : 當集合中的元素分數都一樣時,根據字典順序排序,
// 此命令將獲取字典順序在區間 [min, max] 中的元素總數,當下面選用 '(' 時表示開區間,
// min = '-' 或 '[ | (' + 一個字串,max = '+' 或 '[ | (' + 一個字串
//
// zrangebylex ZSet_Key min max [limit offset count]:根據字典順序獲取在區間 [min, max] 中的所有元素結果集,
// 此命令也只有在集合中的元素分數都一樣的情況下才生效
// limit offset count 為可選欄位,limit 表示限制返回結果集的數量,
// offset 表示從結果集中偏移多少個元素,
// count 表示偏移後再取幾個元素作為返回值
// 示例:以一個分數全相同的 Zset 來測試
zadd testlex 0 a 0 b 0 c 0 cc 0 d 0 e
zlexcount testlex - + // - + 表示無上下限
執行結果:(integer) 6
zlexcount testlex [cc [e // 表示計算 [cc, e] 中的所有元素總數,同 C 語言字串比較方法
執行結果:(integer) 3
zlexcount testlex [cc (e // 表示計算 [cc, e) 中的所有元素總數,同 C 語言字串比較方法
執行結果:(integer) 2
zrangebylex testlex - + // 獲取所有元素
執行結果:
1) "a"
2) "b"
3) "c"
4) "cc"
5) "d"
6) "e"
zrangebylex testlex [cc [e // 獲取區間 [cc, e) 中的所有元素
執行結果:
1) "cc"
2) "d"
3) "e"
zrangebylex testlex - + limit 3 2 // 從開始位置偏移 3 個元素,再取 2 個元素作為結果集返回
執行結果:
1) "cc"
2) "d"
集中瞭解完這個 lex 的概念後,就回到正軌來繼續介紹 zrange、zrevrange、zrangebyscore、zrevrangebyscore、zrank、zrevrank 和 zscore 命令:
// zrange ZSet_Key start stop [withscores]:獲取指定下標區間 [start, stop] 的所有元素,withscores 表示是否攜帶分數
// start 和 stop 與在 List 型別中所瞭解的概念一樣,是索引 index 值
// zrevrange ZSet_Key start stop [withscores]: zrevrange 相當於把這個集合倒置了,比如 zrange 是升序排列,那麼 zrevrange 就是降序排列。
zrange myzset 0 -1 withscores
執行結果:
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "three1"
8) "3"
9) "three2"
10) "3"
11) "three3"
12) "3"
zrange myzset 3 -2
執行結果:
1) "three1"
2) "three2"
zrevrange myzset 3 -2
執行結果:
1) "three"
2) "two"
// zrangebyscore ZSet_Key minscore maxscore [withscores] [limit offset count]: 獲取集合中指定分數區間的元素,
// 重複的欄位就不再解釋了,等會直接看例子
// zrevrangebyscore ZSet_Key maxscore minscore [withscores] [limit offset count]: 原理同 zrevrange,
// 注意分數區間變為了 [maxscore, minscore]
zrangebyscore myzset 2.3 3.0 withscores limit 1 3
執行結果:
1) "three1"
2) "3"
3) "three2"
4) "3"
5) "three3"
6) "3"
zrevrangebyscore myzset 3.0 2.3 withscores limit 1 3
執行結果:
1) "three2"
2) "3"
3) "three1"
4) "3"
5) "three"
6) "3"
// zrank ZSet_Key member : 返回集合中指定元素的索引,從 0 開始
// zrevrange ZSet_Key member : 同理,返回逆序排列中此元素的索引,也是從 0 開始
zrank myzset three
執行結果:(integer) 2
zrevrank myzset three
執行結果:(integer) 3
// zscore ZSet_Key member :返回集合中指定元素的分數
zscore myzset three
執行結果:"3"
修改:zincrby 命令
// zincrby ZSet_Key increment menmber : 將集合中指定元素的分數增加 increment,並返回此元素最終的分數
zincrby myzset 10.5 one
執行結果:"11.5"
刪除:zrem、zremrangebylex、zremrangebyrank 和 zremrangebyscore 命令
// zrem ZSet_Key member1 [member2] [...] :移除集合中一個或多個元素,返回成功移除的個數
zrem myzset three1 three2
執行結果:(integer) 2
// zremrangebyscore ZSet_Key minscore maxscore:移除集合中指定分數閉區間內的所有元素,返回成功移除的個數
zremrangebyscore myzset 1.35 2.88
執行結果:(integer) 1
// zremrangebyrank ZSet_Key start stop :移除集合中指定索引閉區間內的所有元素,返回成功移除的個數
zremrangebyrank myzset 2 -1
執行結果:(integer) 1
// zremrangebylex ZSet_Key min max :移除集合(這個命令執行完後所有元素的分數都是 3,所以 lex 排序生效)
// 中指定字典排序閉區間內的所有元素,返回成功移除的個數
zremrangebylex myzset [three [three
執行結果:(integer) 1
集合的交併運算
首先,在原有基礎上,執行以下命令,新增一個 ZSet 集合:
zadd zset 1 one 2 two
zadd myzset 1 one 2 two
然後先來看並運算:
// zunionstore destination key_num ZSet_Key_1 [ZSet_Key2] [...] [weights weight1 [weight2] [...]] [aggregate (sum | min | max)]
// destination 表示結果集存放到這裡,key_num 表示指定數量的 ZSet 集合參與並運算,
// weights 後面跟著 key_num 個數字,與前面 key_num 個 ZSet 集合一一對應,表示一個集合裡的所有元素在合併的時候要乘以這個因子,預設為 1
// aggregate 表示合併時分佈在不同集合中的相同元素的分數要怎麼取,sum 表示累加,min 表示取最小的,max 取最大的,預設為 sum
// 返回新集合的元素總數,示例:
zunionstore out 2 myzset zset weights 2 3 aggregate sum
執行結果:(integer) 3
zrange out 0 -1 withscores
執行結果:
1) "one"
2) "5"
3) "three3"
4) "6"
5) "two"
6) "10"
交運算同理,示例:
// zinterstore destination key_num ZSet_Key_1 [ZSet_Key2] [...] [weights weight1 [weight2] [...]] [aggregate (sum | min | max)]
zinterstore in 2 myzset zset weights 2 3 aggregate sum
執行結果:(integer) 2
zrange in 0 -1 withscores
執行結果:
1) "one"
2) "5"
3) "two"
4) "10"