go-redis 使用Scan遍歷redis中所有key值


redis中獲取所有key值的方式有兩種,一種是keys方式,另外一個方式,是使用迭代器的方式Scan。

在key值很多的情況下,如果使用keys,就有可能發生阻塞,因為redis是單線程的。

keys命令的時間復雜度是O(N),是遍歷算法,會容易導致redis的服務卡頓。

Scan的時間復雜度同樣也是O(N),但是scan是分次進行的,不會阻塞線程,並且提供了limit參數,可以控制每次返回結果的最大條數

redis的結構是使用了Hash表作為底層實現的,原因不外乎高效而且實現簡單。redis的底層key的存儲結構就是類似於HashMap那樣的數組+鏈表的結構。其中第一維數組的大小為2n(n>=0),每次擴容數組長度就會擴大一倍。

scan命令就是對這個一維數組進行遍歷。每次返回的游標值也都是這個數組的索引。limit參數表示遍歷多少個數組的元素。將這些元素下掛接的符合條件的結果都返回。因為每個元素下掛接的鏈表大小不同,所以每次返回的結果數量也不同。

 

go的代碼實現:

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

var rdb *redis.Client

func initRedis() (err error) {
	ctx,cancel := context.WithTimeout(context.Background(),time.Second*10)
	defer cancel()
	rdb = redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379",
		Password: "",
		PoolSize: 200,
	})
	_,err = rdb.Ping(ctx).Result()
	if err !=nil{
		fmt.Println("ping redis failed err:",err)
		return err
	}
	return nil
}

func main() {
	err := initRedis()
	if err !=nil{
		fmt.Println("init redis failed err :",err)
		return
	}
	ctx := context.Background()

	var cursor uint64
	keys,cursor,err := rdb.Scan(ctx,cursor,"*",100).Result()
	if err !=nil{
		fmt.Println("scan keys failed err:",err)
		return
	}
	for _,key := range keys{
		//fmt.Println("key:",key)
		sType,err := rdb.Type(ctx,key).Result()
		if err !=nil{
			fmt.Println("get type failed :",err)
			return
		}
		fmt.Printf("key :%v ,type is %v\n",key,sType)
		if sType == "string" {
			val,err := rdb.Get(ctx,key).Result()
			if err != nil{
				fmt.Println("get key values failed err:",err)
				return
			}
			fmt.Printf("key :%v ,value :%v\n",key,val)
		}else if sType == "list"{
			val,err := rdb.LPop(ctx,key).Result()
			if err !=nil{
				fmt.Println("get list value failed :",err)
				return
			}
			fmt.Printf("key:%v value:%v\n",key,val)
		}
	}
}

  

 


免責聲明!

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



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