前言

由於redis的keys命令是線上禁用,所以就有了SCANSSCANHSCANZSCAN四個命令。

但是這四個命令也不是每次返回全部匹配結果,因此需要一遍遍執行下去,而且每次返回的cursor要作為下一個的引數。

因此查詢也不太方便,我寫了一個簡單的方法,用來查詢scan的所有結果。關於這幾個命令可以參考【詳細解釋

程式碼分享

package main

import (
"errors"
"flag"
"fmt"
"strings" "github.com/gomodule/redigo/redis"
) func main() {
addr := flag.String("addr", "redis://127.0.0.1:6379", "url")
cmd := flag.String("cmd", "SCAN", "SCAN or SSCAN or HSCAN or ZSCAN")
key := flag.String("key", "", "key")
match := flag.String("match", "", "MATCH pattern")
count := flag.Int("count", 10, "COUNT count")
max := flag.Int("max", 1000, "max count")
flag.Parse() err := scanHandle(*addr, *cmd, *key, *match, *count, *max)
if err != nil {
fmt.Println(err)
}
} func scanHandle(addr, cmd, key, match string, count, max int) error {
switch cmd = strings.ToUpper(cmd); cmd {
case "SCAN", "SSCAN", "HSCAN", "ZSCAN":
default:
return errors.New("cmd error")
} c, err := redis.DialURL(addr)
if err != nil {
return err
}
defer c.Close() var (
i = 0 // cursor下標位置
cursor = 0 // 預設從0開始
args = make([]interface{}, 0, 5)
) if cmd != "SCAN" {
if key == "" {
return errors.New(cmd + " must have key")
}
args = append(args, key)
i++
} args = append(args, cursor)
if match != "" {
args = append(args, "MATCH", match)
}
if count <= 0 {
count = 16
}
args = append(args, "COUNT", count) for {
args[i] = cursor
res, err := redis.Values(c.Do(cmd, args...))
if err != nil {
return err
} var tmp []string
_, err = redis.Scan(res, &cursor, &tmp)
if err != nil {
return err
} if lt := len(tmp); lt > 0 {
for _, v := range tmp {
// 列印結果
fmt.Println(v)
} if max -= lt; max <= 0 {
break
}
} if cursor == 0 {
break // 查詢結束
}
}
return nil
}

總結

其實我們應該避免查詢相關key,因為程式碼裡面會儲存相應的key,而且可以通過設定過期時間自動刪除相關key。

不過redis提供了scan等方案,雖然可以達到效果,但是使用上是存在一點不方便的,總之應該儘量避免這些邏輯。