go-redis | 青训营

84 阅读5分钟

go-redis

背景

Redis 是一个基于内存的非关系型数据库,在项目开发中使用非常广泛,Go 语言操作 Redis 需要使用三方包,我们选择支持 Redis 集群和 Redis 哨兵的 go-redis 包来讲述 Go 语言如何操作 Redis。

配置

go-redis 包需要使用支持 Modules 的 Go 版本,并且使用导入版本控制。所以需要确保初始化 go module。

如果你配置的 go 是按章 GOPATH 配置的,那么新建项目可能没有 go. mod 文件,那么:

go mod init package_name

安装go-redis:

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

使用

版权声明:本文为 CSDN 博主「lena7」的原创文章,遵循 CC 4.0 BY-SA 版权协议 原文链接:golang:使用go-redis连接并操作Redis_golang redis 监控_lena7的博客-CSDN博客

其中有我自己实践的碰壁和其他的学习内容。。。

启动执行

启动 redis 服务器:

redis-server

启动 redis 客户端, 并监示:

~$ redis-cli
127.0.0.1:6379> monitor
OK

go 连接 redis: Redis 有 16 个数据库(0~15),我们使用第 0 个

package main

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

func main() {
	rd := redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:6379", // url
		Password: "",
		DB:       0, // 0号数据库
	})
	result, err := rd.Ping().Result()
	if err != nil {
		fmt.Println("ping err :", err)
		return
	}
	fmt.Println(result)
}

执行后,redis-cli 打印了该信息:

1692523437.159068 [0 127.0.0.1:60030] "ping"

在执行上面的代码的时候,

出现的一些问题 :

重复打开 redis-server 导致的--> ~$ redis-server 5290: C 20 Aug 01:21:23.590 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf 5290: M 20 Aug 01:21:23.591 * Increased maximum number of open files to 10032 (it was originally set to 1024). 5290: M 20 Aug 01:21:23.591 # Creating Server TCP listening socket *:6379: bind: Address already in use

可以使用 lsof -i:6379 命令来查看占用该端口的进程,然后根据需要关闭该进程或更改 Redis 服务器的配置以使用其他端口。 因为当时在终端执行力 redis-server 后来直接叉掉终端,并没有使 redis 服务端终止。 启动后就会一直在后台运行,Ctrl+c 或关闭终端退出

go. mod 文件--> 因为最开始导入包的时候,没理解到 go. mod 应该放在那里

Go 工具链在查找 go.mod 文件时,会从当前目录开始向上搜索,直到找到一个 go.mod 文件或到达文件系统的根目录。因此,如果您的 go.mod 文件位于项目根目录下的子目录中,那么您需要在运行 Go 命令时指定该文件的位置。

如果 go. mod 放在当前项目的父目录的其他子目录下,那么就是:

如果我的项目根目录为 /home/gxz/Documents/code/gowork, 并且我的 go.mod 文件位于 /home/gxz/Documents/code/gowork/pkg/go.mod, 但是我的程序在 /home/gxz/Documents/code/gowork/src/ConnRedis.go 那么您可以使用以下命令来运行程序:

cd /home/gxz/Documents/code/gowork/pkg
go run ../src/ConnRedis.go

这样太麻烦了。。。

所以我当时想法在 GOPATH 根目录下创建 go. mod,但是在我导入依赖的时候出现了报错: ~/Documents/code/goworkgogetgithub.com/goredis/redis/v8go get github.com/go-redis/redis/v8 GOPATH/go.mod exists but should not

GOPATH 目录下存在一个 go.mod 文件,但它不应该存在。当您在使用 Go 模块时,Go 工具链会优先使用 go.mod 文件来管理项目的依赖关系,而不是使用 GOPATH。因此,如果您的 GOPATH 目录下存在一个 go.mod 文件,它可能会干扰 Go 工具链对项目依赖关系的管理。

所以根据之前建 GPOPATH 结构时分成的三个目录 bin(运行结果,这个 GoLand 里面是在运行时调设置的地方修改的), src (项目源代码), pkg (各种依赖之类的东西),所以把 go. mod 弄在 src 中,这样 src 下的项目源码都可以找到这个 go. mod

之后还是出现找不到依赖的问题,因为我是在 ubuntu 的 vscode 中运行的,直接点的那个三角,就一直有问题,后来改成用终端就好了。。。(前提是我把代码找不到的依赖改好了,它会有修改提示,按道理没问题的,结果,所以还是终端)

回归正题 :

简单操作 redis set 操作:Set (key, value, 过期时间). Err (),如有错误返回错误信息 get 操作:Get (key). Result (),返回获取参数和错误信息(无错误则为 nil) 注意:当 get 获取一个不存在的 value 时,错误信息会返回 redis. nil,这时候要记得区分。

package main

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

// 全局变量:连接数据库
// 将redis连接获取到的`*redis.Client`对象作为全局变量,供后续操作
var rd *redis.Client = redis.NewClient(&redis.Options{
	Addr:     "127.0.0.1:6379", // url
	Password: "",
	DB:       0, // 数据库
})

// string操作
func SetAndGet() {
	// set操作:第三个参数是过期时间,如果是0表示不会过期。
	err := rd.Set("k1", "v1", 0).Err()
	if err != nil {
		fmt.Println("set err :", err)
		return
	}
	// get操作
	val, err := rd.Get("k1").Result()
	if err != nil {
		fmt.Println("get err :", err)
		return
	}
	fmt.Println("k1 ==", val) // k1 == v1
	// get获取一个不存在的key,err会返回redis.Nil,因此要注意判断err
	val2, err := rd.Get("k2").Result()
	if err == redis.Nil {
		fmt.Println("k2 does not exist") // k2 does not exist
	} else if err != nil {
		panic(err)
	} else {
		fmt.Println("k2", val2)
	}

	// 添加添加多个值
	rd.SAdd("key", "v1", "v2", "v3")
	// 取出全部元素
	members := rd.SMembers("key")
	for _, value := range members.Val() {
		fmt.Printf("%s\t", value) // v2	v1	v3
	}
	fmt.Println()
	// 删除某个元素
	rd.SRem("key", "v2")
	// 判断某个元素是否存在
	fmt.Println(rd.SIsMember("key", "v2").Val()) // false
	// 获取当前set集合的长度
	fmt.Println(rd.SCard("key")) // scard key: 2
	rd.Close()                   // 记得关闭连接
}

func main() {
	SetAndGet()
}

运行结果:

~/Documents/code/gowork/src/Go-Redis$ go run ConnRedis.go 
k1 == v1
k2 does not exist
v2      v3      v1
false
scard key: 2

redis-cli 客户端:

~$ redis-cli
127.0.0.1:6379> monitor
OK
1692539369.951347 [0 127.0.0.1:60256] "set" "k1" "v1"
1692539369.951501 [0 127.0.0.1:60256] "get" "k1"
1692539369.951722 [0 127.0.0.1:60256] "get" "k2"
1692539369.951817 [0 127.0.0.1:60256] "sadd" "key" "v1" "v2" "v3"
1692539369.951998 [0 127.0.0.1:60256] "smembers" "key"
1692539369.952242 [0 127.0.0.1:60256] "srem" "key" "v2"
1692539369.952382 [0 127.0.0.1:60256] "sismember" "key" "v2"
1692539369.952530 [0 127.0.0.1:60256] "scard" "key"

检验:

~$ redis-cli
127.0.0.1:6379> get k1
"v1"

还有对应哈希的操作:

func HashOperations() {
	// 设置哈希表中的字段值
	err := rd.HSet("myhash", "field1", "value1").Err()
	if err != nil {
		fmt.Println("HSet err:", err)
		return
	}

	// 获取哈希表中的字段值
	val, err := rd.HGet("myhash", "field1").Result()
	if err != nil {
		fmt.Println("HGet err:", err)
		return
	}
	fmt.Println("field1:", val) // field1: value1

	// 获取哈希表中不存在的字段值,err会返回redis.Nil,因此要注意判断err
	val2, err := rd.HGet("myhash", "field2").Result()
	if err == redis.Nil {
		fmt.Println("field2 does not exist") // field2 does not exist
	} else if err != nil {
		panic(err)
	} else {
		fmt.Println("field2:", val2)
	}

	// 一次性设置多个字段值
	rd.HMSet("myhash", map[string]interface{}{
		"field2": "value2",
		"field3": "value3",
	})

	// 一次性获取多个字段值
	vals, err := rd.HMGet("myhash", "field1", "field2", "field3").Result()
	if err != nil {
		fmt.Println("HMGet err:", err)
		return
	}
	fmt.Println("fields:", vals) // fields: [value1 value2 value3]

	rd.Close() // 记得关闭连接
}

结果如下:

field1: value1
field2 does not exist
fields: [value1 value2 value3]