1. 程式人生 > 遊戲資訊 >WBG被JDG淘汰官博炸鍋!Theshy選劍魔被質疑眾解說發文感嘆,369採訪誅心了

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"