主頁 > 後端開發 > Go語言之 go-redis 基本使用

Go語言之 go-redis 基本使用

2023-06-17 07:25:27 後端開發

Go語言之 go-redis 基本使用

Redis 介紹

Redis:https://redis.io/

Redis 中文網:https://www.redis.net.cn/

REmote DIctionary Server(Redis) 是一個由Salvatore Sanfilippo寫的key-value存盤系統,

Redis是一個開源的使用ANSI C語言撰寫、遵守BSD協議、支持網路、可基于記憶體亦可持久化的日志型、Key-Value資料庫,并提供多種語言的API,

它通常被稱為資料結構服務器,因為值(value)可以是 字串(String), 哈希(Map), 串列(list), 集合(sets) 和 有序集合(sorted sets)等型別,

macOS 安裝Redis

brew install redis

Windows 安裝 Redis

下載地址:https://github.com/dmajkic/redis/tags/

https://github.com/ServiceStack/redis-windows

https://github.com/microsoftarchive/redis/releases

go-redis 使用

安裝 go-redis 庫 https://github.com/redis/go-redis

go get github.com/redis/go-redis/v9

Go-Redis 中文檔案:https://redis.uptrace.dev/zh/

安裝

go-redis 支持 2 個最新的 go 版本且依賴Go modules,如果 你還沒有 go mod,你需要首先初始化:

go mod init github.com/my/repo

安裝 go-redis/v9 (支持所有的 redis 版本):

go get github.com/redis/go-redis/v9

#連接到 Redis 服務器

連接到 Redis 服務器示例,更多配置引數,請參照 redis.Options:

import "github.com/redis/go-redis/v9"

rdb := redis.NewClient(&redis.Options{
	Addr:	  "localhost:6379",
	Password: "", // 沒有密碼,默認值
	DB:		  0,  // 默認DB 0
})

同時也支持另外一種常見的連接字串:

opt, err := redis.ParseURL("redis://<user>:<pass>@localhost:6379/<db>")
if err != nil {
	panic(err)
}

rdb := redis.NewClient(opt)

#使用 TLS

你需要手動設定 tls.Config,你可以在 這里 了解相關 tls.Config更多的配置資訊:

rdb := redis.NewClient(&redis.Options{
	TLSConfig: &tls.Config{
		MinVersion: tls.VersionTLS12,
		ServerName: "you domain",
		//Certificates: []tls.Certificate{cert}
	},
})

如果你使用的是域名連接,且遇到了類似 x509: cannot validate certificate for xxx.xxx.xxx.xxx because it doesn't contain any IP SANs的錯誤 ,應該在 ServerName 中指定你的域名:更多詳情請參考本鏈接

rdb := redis.NewClient(&redis.Options{
	TLSConfig: &tls.Config{
		MinVersion: tls.VersionTLS12,
		ServerName: "你的域名",
	},
})

#SSH 方式

使用 SSH 協議連接:

sshConfig := &ssh.ClientConfig{
	User:			 "root",
	Auth:			 []ssh.AuthMethod{ssh.Password("password")},
	HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	Timeout:		 15 * time.Second,
}

sshClient, err := ssh.Dial("tcp", "remoteIP:22", sshConfig)
if err != nil {
	panic(err)
}

rdb := redis.NewClient(&redis.Options{
	Addr: net.JoinHostPort("127.0.0.1", "6379"),
	Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
		return sshClient.Dial(network, addr)
	},
	// SSH不支持超時設定,在這里禁用
	ReadTimeout:  -1,
	WriteTimeout: -1,
})

#dial tcp: i/o timeout

當你遇到 dial tcp: i/o timeout 錯誤時,表示 go-redis 無法連接 Redis 服務器,比如 redis 服務器沒有 正常運行或監聽了其他埠,以及可能被防火墻攔截等,你可以使用一些網路命令排查問題,例如 telnet:

telnet localhost 6379
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused

如果你使用 Docker、Kubernetes、Istio、Service Mesh、Sidecar 方式運行,應該確保服務在容器完全可用后啟 動,你可以通過參考該地址、Readiness Gate、Istio holdApplicationUntilProxyStarts等,

Context 背景關系

go-redis 支持 Context,你可以使用它控制 超時 或者傳遞一些資料, 也可以 監控 go-redis 性能,

ctx := context.Background()

go-redis 實操 https://pkg.go.dev/github.com/go-redis/redis

安裝

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? go get github.com/redis/go-redis/v9
go: downloading github.com/redis/go-redis/v9 v9.0.5
go: downloading github.com/redis/go-redis v6.15.9+incompatible
go: downloading github.com/cespare/xxhash/v2 v2.2.0
go: downloading github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
go: added github.com/cespare/xxhash/v2 v2.2.0
go: added github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
go: added github.com/redis/go-redis/v9 v9.0.5

Code/go/redis_demo via ?? v1.20.3 via ?? base took 2.4s 
? 

連接 Redis 服務器并初始化

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base took 2.1s 
? go run main.go
initRedisClient started successfully

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? 

執行 Redis 命令

執行 Redis 命令:

val, err := rdb.Get(ctx, "key").Result()
fmt.Println(val)

你也可以分別訪問值和錯誤:

get := rdb.Get(ctx, "key")
fmt.Println(get.Val(), get.Err())

執行尚不支持的命令

可以使用 Do() 方法執行尚不支持或者任意命令:

val, err := rdb.Do(ctx, "get", "key").Result()
if err != nil {
	if err == redis.Nil {
		fmt.Println("key does not exists")
		return
	}
	panic(err)
}
fmt.Println(val.(string))

Do() 方法回傳 Cmd 型別,你可以使用它獲取你 想要的型別:

// Text is a shortcut for get.Val().(string) with proper error handling.
val, err := rdb.Do(ctx, "get", "key").Text()
fmt.Println(val, err)

方法串列:

s, err := cmd.Text()
flag, err := cmd.Bool()

num, err := cmd.Int()
num, err := cmd.Int64()
num, err := cmd.Uint64()
num, err := cmd.Float32()
num, err := cmd.Float64()

ss, err := cmd.StringSlice()
ns, err := cmd.Int64Slice()
ns, err := cmd.Uint64Slice()
fs, err := cmd.Float32Slice()
fs, err := cmd.Float64Slice()
bs, err := cmd.BoolSlice()

#redis.Nil

redis.Nil 是一種特殊的錯誤,嚴格意義上來說它并不是錯誤,而是代表一種狀態,例如你使用 Get 命令獲取 key 的值,當 key 不存在時,回傳 redis.Nil,在其他比如 BLPOPZSCORE 也有類似的回應,你需要區 分錯誤:

val, err := rdb.Get(ctx, "key").Result()
switch {
case err == redis.Nil:
	fmt.Println("key不存在")
case err != nil:
	fmt.Println("錯誤", err)
case val == "":
	fmt.Println("值是空字串")
}

Conn

redis.Conn 是從連接池中取出的單個連接,除非你有特殊的需要,否則盡量不要使用它,你可以使用它向 redis 發送任何資料并讀取 redis 的回應,當你使用完畢時,應該把它回傳給 go-redis,否則連接池會永遠丟失一個連 接,

cn := rdb.Conn(ctx)
defer cn.Close()

if err := cn.ClientSetName(ctx, "myclient").Err(); err != nil {
	panic(err)
}

name, err := cn.ClientGetName(ctx).Result()
if err != nil {
	panic(err)
}
fmt.Println("client name", name)

基本使用 執行命令

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}

// doCommand go-redis基本使用示例
func redisCommand() {
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	// 獲取Redis的“Get key”命令,它回傳redis,當鍵不存在時出現Nil錯誤,
	val, err := rdb.Get(ctx, "key").Result()
	if err != nil {
		fmt.Printf("redis command failed: %v\n", err)
	}
	fmt.Printf("redis command get key %v\n", val)

	// 分別訪問值和錯誤:
	get := rdb.Get(ctx, "key")
	fmt.Println("redis command get value: ", get.Val()) // 獲取值
	fmt.Println("redis command get err: ", get.Err())   // 獲取錯誤

	// 設定Redis ' Set key value [expiration] '命令,
	err = rdb.Set(ctx, "key", 10, time.Hour).Err()
	fmt.Printf("rdb set err: %v\n", err)

	// 獲取Redis的“Get key”命令,它回傳redis,當鍵不存在時出現Nil錯誤,
	value := rdb.Get(ctx, "key").Val()
	fmt.Printf("rdb get value: %v\n", value)
}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,

	redisCommand()
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? go run main.go
initRedisClient started successfully
redis command failed: redis: nil
redis command get key 
redis command get value:  
redis command get err:  redis: nil
rdb set err: <nil>
rdb get value: 10

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? 

Go Redis 配置

Redis Client

type Options struct {
    // 連接網路型別,如: tcp、udp、unix等方式
    // 如果為空默認tcp
    Network string
	
    // redis服務器地址,ip:port格式,比如:192.168.1.100:6379
    // 默認為 :6379
    Addr string
    
    // ClientName 是對網路連接設定一個名字,使用 "CLIENT LIST" 命令
    // 可以查看redis服務器當前的網路連接串列
    // 如果設定了ClientName,go-redis對每個連接呼叫 `CLIENT SETNAME ClientName` 命令
    // 查看: https://redis.io/commands/client-setname/
    // 默認為空,不設定客戶端名稱
    ClientName string
	
    // 如果你想自定義連接網路的方式,可以自定義 `Dialer` 方法,
    // 如果不指定,將使用默認的方式進行網路連接 `redis.NewDialer`
    Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
    
    // 建立了新連接時呼叫此函式
    // 默認為nil
    OnConnect func(ctx context.Context, cn *Conn) error
	
    // 當redis服務器版本在6.0以上時,作為ACL認證資訊配合密碼一起使用,
    // ACL是redis 6.0以上版本提供的認證功能,6.0以下版本僅支持密碼認證,
    // 默認為空,不進行認證,
    Username string

    // 當redis服務器版本在6.0以上時,作為ACL認證資訊配合密碼一起使用,
    // 當redis服務器版本在6.0以下時,僅作為密碼認證,
    // ACL是redis 6.0以上版本提供的認證功能,6.0以下版本僅支持密碼認證,
    // 默認為空,不進行認證,
    Password string
	
    // 允許動態設定用戶名和密碼,go-redis在進行網路連接時會獲取用戶名和密碼,
    // 這對一些認證鑒權有時效性的系統來說很有用,比如一些云服務商提供認證資訊有效期為12小時,
    // 默認為nil
    CredentialsProvider func() (username string, password string)
    
    // redis DB 資料庫,默認為0
    DB int
    
    // 命令最大重試次數, 默認為3
    MaxRetries int
	
    // 每次重試最小間隔時間
    // 默認 8 * time.Millisecond (8毫秒) ,設定-1為禁用
    MinRetryBackoff time.Duration

    // 每次重試最大間隔時間
    // 默認 512 * time.Millisecond (512毫秒) ,設定-1為禁用
    MaxRetryBackoff time.Duration
    
    // 建立新網路連接時的超時時間
    // 默認5秒
    DialTimeout time.Duration
	
    // 從網路連接中讀取資料超時時間,可能的值:
    //  0 - 默認值,3秒
    // -1 - 無超時,無限期的阻塞
    // -2 - 不進行超時設定,不呼叫 SetReadDeadline 方法
    ReadTimeout time.Duration
	
    // 把資料寫入網路連接的超時時間,可能的值:
    //  0 - 默認值,3秒
    // -1 - 無超時,無限期的阻塞
    // -2 - 不進行超時設定,不呼叫 SetWriteDeadline 方法
    WriteTimeout time.Duration
	
    // 是否使用context.Context的背景關系截止時間,
    // 有些情況下,context.Context的超時可能帶來問題,
    // 默認不使用
    ContextTimeoutEnabled bool

    // 連接池的型別,有 LIFO 和 FIFO 兩種模式,
    // PoolFIFO 為 false 時使用 LIFO 模式,為 true 使用 FIFO 模式,
    // 當一個連接使用完畢時會把連接歸還給連接池,連接池會把連接放入隊尾,
    // LIFO 模式時,每次取空閑連接會從"隊尾"取,就是剛放入隊尾的空閑連接,
    // 也就是說 LIFO 每次使用的都是熱連接,連接池有機會關閉"隊頭"的長期空閑連接,
    // 并且從概率上,剛放入的熱連接健康狀態會更好;
    // 而 FIFO 模式則相反,每次取空閑連接會從"隊頭"取,相比較于 LIFO 模式,
    // 會使整個連接池的連接使用更加平均,有點類似于負載均衡尋輪模式,會回圈的使用
    // 連接池的所有連接,如果你使用 go-redis 當做代理讓后端 redis 節點負載更平均的話,
    // FIFO 模式對你很有用,
    // 如果你不確定使用什么模式,請保持默認 PoolFIFO = false
    PoolFIFO bool

    // 連接池最大連接數量,注意:這里不包括 pub/sub,pub/sub 將使用獨立的網路連接
    // 默認為 10 * runtime.GOMAXPROCS
    PoolSize int
	
    // PoolTimeout 代表如果連接池所有連接都在使用中,等待獲取連接時間,超時將回傳錯誤
    // 默認是 1秒+ReadTimeout
    PoolTimeout time.Duration
	
    // 連接池保持的最小空閑連接數,它受到PoolSize的限制
    // 默認為0,不保持
    MinIdleConns int
	
    // 連接池保持的最大空閑連接數,多余的空閑連接將被關閉
    // 默認為0,不限制
    MaxIdleConns int

    // ConnMaxIdleTime 是最大空閑時間,超過這個時間將被關閉,
    // 如果 ConnMaxIdleTime <= 0,則連接不會因為空閑而被關閉,
    // 默認值是30分鐘,-1禁用
    ConnMaxIdleTime time.Duration

    // ConnMaxLifetime 是一個連接的生存時間,
    // 和 ConnMaxIdleTime 不同,ConnMaxLifetime 表示連接最大的存活時間
    // 如果 ConnMaxLifetime <= 0,則連接不會有使用時間限制
    // 默認值為0,代表連接沒有時間限制
    ConnMaxLifetime time.Duration
    
    // 如果你的redis服務器需要TLS訪問,可以在這里配置TLS證書等資訊
    // 如果配置了證書資訊,go-redis將使用TLS發起連接,
    // 如果你自定義了 `Dialer` 方法,你需要自己實作網路連接
    TLSConfig *tls.Config
    
    // 限流器的配置,參照 `Limiter` 介面
    Limiter Limiter
    
    // 設定啟用在副本節點只讀查詢,默認為false不啟用
    // 參照:https://redis.io/commands/readonly
    readOnly bool
}

獲取 Redis 值 GET Key

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}


func redisGetKey(key string) (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	val, err := rdb.Get(ctx, key).Result()
	if err != nil {
		if err == redis.Nil {
			return "", nil
			// DeadlineExceeded是Context回傳的錯誤,當背景關系的截止日期過去時發生錯誤,
		} else if err == context.DeadlineExceeded {
			return "", fmt.Errorf("獲取值超時")
		} else {
			return "", fmt.Errorf("獲取值失敗: %v", err)
		}
	}

	if val == "" {
		return "", nil
	}

	return val, nil
}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,

	//redisCommand()

	// get key
	value, _ := redisGetKey("key")
	fmt.Printf("get key: %v\n", value)
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? go run main.go
initRedisClient started successfully
get key: 10

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? 

設定值 SET

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}


func redisSetKey(key string, val string) error {
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	// 設定Redis ' Set key value [expiration] '命令,
	err := rdb.Set(ctx, key, val, time.Hour).Err()
	if err != nil {
		fmt.Printf("redis set failed, err: %v\n", err)
		return err
	}
	return nil

}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,

	// set value
	err := redisSetKey("name", "xia")
	if err != nil {
		fmt.Printf("redisSetKey failed: %v\n", err)
		return
	}
	fmt.Println("redisSetKey succeeded")
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? go run main.go
initRedisClient started successfully
redisSetKey succeeded

HGetAll HSET

127.0.0.1:6379> hset user name "lixia"
(integer) 1
127.0.0.1:6379> hgetall user
1) "name"
2) "lixia"
127.0.0.1:6379> hset user age 14
(integer) 1
127.0.0.1:6379> hgetall user
1) "name"
2) "lixia"
3) "age"
4) "14"
127.0.0.1:6379>

main.go

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}


func hGetDemo(key string) (map[string]string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	val, err := rdb.HGetAll(ctx, key).Result()
	if err != nil {
		// redis.Nil
		// 其它錯誤
		fmt.Printf("hgetall failed, err: %v\n", err)
		return nil, err
	}
	return val, nil
}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,

	// hgetall()
	value, err := hGetDemo("user")
	if err != nil {
		fmt.Printf("hGetDem failed with error: %v\n", err)
		return
	}
	fmt.Printf("hgetall successful, value: %v\n", value)
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base took 3.8s 
? go run main.go 
initRedisClient started successfully
hgetall successful, value: map[age:14 name:lixia]

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? 

HMGet HGet

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}


func hMGetDemo() {
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	val := rdb.HMGet(ctx, "user", "name", "age").Val()
	fmt.Printf("redis HMGet %v\n", val)

	value := rdb.HGet(ctx, "user", "age").Val()
	fmt.Printf("redis HGet value: %v\n", value)
}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,

	hMGetDemo()
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? go run main.go 
initRedisClient started successfully
redis HMGet [lixia 14]
redis HGet value: 14

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? 

ZSET 使用

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}


// zset Demo 操作 zset 示例
func zSetDemo() {
	// key
	zSetKey := "language_rank"
	// value Z表示有序集合的成員,
	languages := []redis.Z{
		{Score: 90.0, Member: "Golang"},
		{Score: 95.0, Member: "Python"},
		{Score: 97.0, Member: "Rust"},
		{Score: 99.0, Member: "C/C++"},
		{Score: 88.0, Member: "Java"},
	}
	// WithTimeout回傳WithDeadline(parent, time.Now(). add (timeout)),
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	// ZAdd Redis `ZADD key score member [score member ...]` command.
	num, err := rdb.ZAdd(ctx, zSetKey, languages...).Result()
	if err != nil {
		fmt.Printf("zadd failed, err:%v\n", err)
		return
	}
	fmt.Printf("zadd successful num: %v\n", num)

	// ZIncrBy 給某一個元素添加分數值 把Golang的分數加 10
	newScore, err := rdb.ZIncrBy(ctx, zSetKey, 10.0, "Golang").Result()
	if err != nil {
		fmt.Printf("ZIncrBy failed, err:%v\n", err)
		return
	}
	fmt.Printf("ZIncrBy success Golang's score is %f now.\n", newScore)

	// 取分數最高的3個  適用于 排行榜、充值榜...
	// ZRevRangeWithScores according to the Redis documentation, if member does not exist
	// in the sorted set or key does not exist, it will return a redis.Nil error.
	ret, err := rdb.ZRevRangeWithScores(ctx, zSetKey, 0, 2).Result()
	if err != nil {
		fmt.Printf("zRevRangeWithScores failed, err: %v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Printf("z.Member: %v, z.Score: %v\n", z.Member, z.Score)
	}

	// 取95~100分的
	op := &redis.ZRangeBy{
		Min: "95",
		Max: "100",
	}
	ret, err = rdb.ZRangeByScoreWithScores(ctx, zSetKey, op).Result()
	if err != nil {
		fmt.Printf("zrangebyscore failed, err:%v\n", err)
		return
	}
	fmt.Printf("zrangebyscore returned %v\n", ret)
	for _, z := range ret {
		fmt.Printf("ZRangeByScoreWithScores success Member: %v, Score: %v\n", z.Member, z.Score)
	}
}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,

	zSetDemo()
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? go run main.go
initRedisClient started successfully
zadd successful num: 5
ZIncrBy success Golang's score is 100.000000 now.
z.Member: Golang, z.Score: 100
z.Member: C/C++, z.Score: 99
z.Member: Rust, z.Score: 97
zrangebyscore returned [{95 Python} {97 Rust} {99 C/C++} {100 Golang}]
ZRangeByScoreWithScores success Member: Python, Score: 95
ZRangeByScoreWithScores success Member: Rust, Score: 97
ZRangeByScoreWithScores success Member: C/C++, Score: 99
ZRangeByScoreWithScores success Member: Golang, Score: 100

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? 

Redis 查詢

127.0.0.1:6379> ZREVRANGE language_rank 0 2
1) "Golang"
2) "C/C++"
3) "Rust"
127.0.0.1:6379> ZREVRANGE language_rank 0 2 withscores
1) "Golang"
2) "100"
3) "C/C++"
4) "99"
5) "Rust"
6) "97"
127.0.0.1:6379> ZRANDMEMBER language_rank
"Rust"
127.0.0.1:6379> ZRANGE language_rank 0 2
1) "Java"
2) "Python"
3) "Rust"
127.0.0.1:6379> ZRANGE language_rank 0 2 withscores
1) "Java"
2) "88"
3) "Python"
4) "95"
5) "Rust"
6) "97"
127.0.0.1:6379> ZINCRBY language_rank 1 "Python"
"96"
127.0.0.1:6379> ZRANGE language_rank 0 2 withscores
1) "Java"
2) "88"
3) "Python"
4) "96"
5) "Rust"
6) "97"
127.0.0.1:6379>

Scan 根據前綴查詢 Key

package main

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

// 宣告一個全域的 rdb 變數
var rdb *redis.Client

// 初始化連接
func initRedisClient() (err error) {
	// NewClient將客戶端回傳給Options指定的Redis Server,
	// Options保留設定以建立redis連接,
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // 沒有密碼,默認值
		DB:       0,  // 默認DB 0 連接到服務器后要選擇的資料庫,
		PoolSize: 20, // 最大套接字連接數, 默認情況下,每個可用CPU有10個連接,由runtime.GOMAXPROCS報告,
	})

	// Background回傳一個非空的Context,它永遠不會被取消,沒有值,也沒有截止日期,
	// 它通常由main函式、初始化和測驗使用,并作為傳入請求的頂級背景關系
	ctx := context.Background()

	_, err = rdb.Ping(ctx).Result()
	if err != nil {
		return err
	}
	return nil
}

func scanKeyDemo(match string) {
	// WithTimeout回傳WithDeadline(parent, time.Now(). add (timeout)),
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()
	// 根據前綴查詢 Key
	iter := rdb.Scan(ctx, 0, match, 0).Iterator()

	for iter.Next(ctx) {
		fmt.Printf("key value: %v\n", iter.Val())
	}

	if err := iter.Err(); err != nil {
		fmt.Printf("rdb scan failed, err: %v\n", err)
		return
	}
}

func main() {
	if err := initRedisClient(); err != nil {
		fmt.Printf("initRedisClient failed: %v\n", err)
		return
	}
	fmt.Println("initRedisClient started successfully")
	defer rdb.Close() // Close 關閉客戶端,釋放所有打開的資源,關閉客戶端是很少見的,因為客戶端是長期存在的,并在許多例程之間共享,

	scanKeyDemo("l*")
}

運行

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? go run main.go
initRedisClient started successfully
key value: language_rank

Code/go/redis_demo via ?? v1.20.3 via ?? base 
? 

本文來自博客園,作者:尋月隱君,轉載請注明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17485294.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555332.html

標籤:其他

上一篇:Scala方法和函式

下一篇:返回列表

標籤雲
其他(161098) Python(38236) JavaScript(25498) Java(18244) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7254) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4599) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) 功能(1967) HtmlCss(1967) Web開發(1951) C++(1941) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Go語言之 go-redis 基本使用

    # Go語言之 go-redis 基本使用 ## Redis 介紹 [Redis](https://redis.io/): [Redis 中文網](https://www.redis.net.cn/): REmote DIctionary Server(Redis) 是一個由Salvatore Sa ......

    uj5u.com 2023-06-17 07:25:27 more
  • Scala方法和函式

    - 方法和函式的作用幾乎是一樣的,但是函式在使用的程序中更加靈活和多樣化 - scala中函式是頭等公民 . 可以作為方法的回傳值和引數使用 - scala是一個集面向物件和面向函式于一身的編程語言 , 靈活的函式是函式式編程的一種體現 - 函式的使用使代碼更加簡潔和靈活 # 函式 scala中一種 ......

    uj5u.com 2023-06-17 07:25:00 more
  • HTTP請求:requests的進階使用方法淺析

    上篇文章講解了requests模塊的基礎使用,其中有get、put、post等多種請求方式,使用data、json等格式做為請求引數,在請求體中添加請求頭部資訊的常見資訊,如:headers、cookies,以及對請求回應的處理方法。接下來講解一下requests的高級用法。 ......

    uj5u.com 2023-06-17 07:24:40 more
  • Python 自動化測驗的配置層實作方式對標與落地

    Python中什么是組態檔,組態檔如何使用,有哪些支持的組態檔等內容,話不多說,讓我們一起看看吧~ ## 1 什么是組態檔? 組態檔是用于配置計算機程式的引數和初始化設定的檔案,如果沒有這些配置程式可能無法運行或是影響運行(運行速度、便捷性等),使用組態檔的好處在于,部分內容以及環境運行 ......

    uj5u.com 2023-06-17 07:24:35 more
  • 內網環境下批量安裝python庫

    最近組里安排了新內網,又要配環境。 眾所周知,內網安裝python庫需要先到www.pypi.org找到對應版本的包,然后再下載whl檔案,上傳到內網,再用`pip install "檔案地址"`去安裝。 這樣就會出現一個問題,鬼知道這個包需要的前置依賴是什么,pip會自動檢查前置依賴,然后自動從源 ......

    uj5u.com 2023-06-17 07:24:27 more
  • 如何有效管理爬蟲流量?

    本文分享自天翼云開發者社區《如何有效管理爬蟲流量?》,作者:劉****海 據國際知名金融廣告服務平臺提供商Dianomi的報告《2018 Robot traffic report》的資料,在互聯網上人類流量僅僅占了48.2%,也就是說,一個頁面的10000個點擊里面,大約5100個來自機器人。在航旅 ......

    uj5u.com 2023-06-17 07:24:15 more
  • Python初學者友好丨詳解引數傳遞型別

    摘要: 本文清晰地解釋了Python中的不同引數傳遞型別,并提供了示例代碼來說明每種型別的用法。對于初學者或不清楚Python傳參的讀者們來說是非常有益的,文中提供了足夠的資訊來理解和使用Python中的函式引數傳遞。 本文分享自華為云社區《提升Python函式呼叫靈活性:引數傳遞型別詳解》,作者: ......

    uj5u.com 2023-06-17 07:24:11 more
  • HTTP請求:requests模塊基礎使用必知必會

    http請求是常見的一種網頁協議,我們看到的各種網頁,其實都是發送了http請求得到了服務器的回應,從而將資料庫中復雜的資料以簡單、直觀的方式呈現出來,方便大眾閱讀、使用。而如何發送http請求呢?今天來探討一下使用requests模塊,達到高效、簡單的http請求操作。 ......

    uj5u.com 2023-06-17 07:24:07 more
  • 01. 組建知識星球服務體系

    ## 一、初衷: 因為想要進行各種技術點的訓練和學習,開發中需要使用各種各樣的開源技術框架,苦于沒有基礎服務支撐,所以想要建立一個專門的服務支撐系統,每年購買的云服務器配置底下,安裝一個Jenkins都跑不起來,所以自己購買了一個物理主機,記憶體加裝到`32G`,搭建自己的私人技術知識星球。 搭建一套 ......

    uj5u.com 2023-06-17 07:23:43 more
  • RabbitMQ快速使用代碼手冊

    本篇博客的內容為RabbitMQ在開發程序中的快速上手使用,側重于代碼部分,幾乎沒有相關概念的介紹,相關概念請參考以下csdn博客,兩篇都是我找的精華帖,供大家學習。本篇博客也持續更新~~~ ......

    uj5u.com 2023-06-17 07:23:38 more