redis中使用SCAN代替KEYS


前言

由於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等方案,雖然可以達到效果,但是使用上是存在一點不方便的,總之應該盡量避免這些邏輯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM