前言
由於redis的keys命令是線上禁用,所以就有了
SCAN
、SSCAN
、HSCAN
和ZSCAN
四個命令。
但是這四個命令也不是每次返回全部匹配結果,因此需要一遍遍執行下去,而且每次返回的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等方案,雖然可以達到效果,但是使用上是存在一點不方便的,總之應該儘量避免這些邏輯。