Redis是我们开发应用程序中很常用的NoSQL数据库,作为一款内存数据库,Redis也支持数据持久化(RDB与AOF两种机制),所以Redis既可以作为数据库来使用,也可以作为关系型数据库与应用程序之间的缓存来使用。
那么在Go语言中要如何连接和操作Redis呢?在这篇文章中,我们一起来探究一下!
开始
在开始操作Redis之前,我们先来初始化我们的示例项目,接着再安装连接Redis所需要的第三方库。
初始化项目
由于我们接下来要用到的第三方库需要Go Moudles的支持,因此我们先使用go mod init命令初始化我们的示例项目:
go mod init GoTest
Go Redis
由于Go语言的标准库并没有提供对Redis的支持,因此就需要使用到Go社区的第三方库。
在这里推荐用Go Reids,该库最新版本的Github地址为:
github.com/redis/go-redis
为什么推荐使用Go Redis
推荐使用Go Redis的原因有以下几点:
Go Redis是Redis官方推荐的第三方库。- 社区中使用的人也比较多,而且文档很齐全。
- 支持不同种类的
Redis客户端,比如哨兵客户端,集群客户端等。 - 支持所有的
Redis版本。
Go Redis安装
通过cd命令进入项目,执行go get命令就可以下载安装 github.com/redis/go-redis/v9:
cd GoTest #最新版本为v9 go get github.com/redis/go-redis/v9
连接Redis
如同所有的Client/Server应用程序一样,要想操作Redis,就必须先与Redis建立网络连接。
简单连接
如果是连接部署在内部网络没有密码的Redis服务器,只需要IP与端口号(port)就可以连接了:
import "github.com/redis/go-redis/v9"
opt := &redis.Options{
Addr: "localhost:6379",
}
rdb := redis.NewClient(opt)上面代码中,可以概述为以下两个步骤:
- 实例化一个
redis.Options表示连接配置对象,该对象当前设置了Addr字段,该 字段表示Redis服务器的地址。 - 将
redis.Options对象传给redis.NewClient()函数,redis.NewClient()函数会返回一个操作Redis的句柄rdb。
redis.ParseURL
除了自定义redis.Options,另一种方式是调用redis.ParseURL()函数以下格式的URL,该函数会返回一个redis.Options对象:
redis://<user>:<pass>@localhost:6379/<port>
因此我们可以将上面连接Redis的例子改写为:
import "github.com/redis/go-redis/v9"
opt, err := redis.ParseURL("redis://localhost:6379")
if err != nil {
panic(err)
}
rdb := redis.NewClient(opt)redis.Options
前面我们连接Redis的例子中只用到了redis.Options的Addr字段:
opt := &redis.Options{
Addr: "localhost:6379",
}除此之外,我们也可以通过redis.Options的字段配置连接的参数:
opt := &redis.Options{
//地址与端口
Addr: "localhost:6379",
//数据库,0~16
DB:0,
//用户名,在Redis6.0以上使用
Username:"test",
//密码
Password:"123456",
//命令最大重试次数
MaxRetries:3,
//连接超时
DialTimeout:3,
//连接池
PoolSize:30,
//最小空闲连接数
MinIdleConns:10,
//最大空闲连接数
MaxIdleConns:30,
}上面列举的是redis.Options比较常用的字段,实际上还有很多其他的字段参数,这里就不一一列举了。
Redis操作
虽然已经通过redis.NewClient()函数获取操作Redis的句柄了,但要操作Redis了,还需要创建一个Context对象,这是因为所有的Go Redis操作Redis的方法的第一个参数都是Context。
创建Context
Context表示上下文,可以用于超时控制、数据传递以及性能监控等。
通过context包的Backgroud()函数可以创建一个根Context:
ctx := context.Background()
执行已支持的命令
Go Redis为所有的Redis命令都提供了对应的方法,比如SET命令对应的方法为Set,HGET对应的方法为HGet。
因此如果想执行对应的Redis命令,直接调用对应的方法即可,比如:
redis> set test test_value 0 redis> hset user:1 id 1 name 小张 gender 男
使用Go Redis执行上面命令的代码为:
rdb.Set(ctx, "test", "test_value", 0) rdb.HSet(ctx, "user:1", "id",1,"name", "小张", "gender", "男")
Redis命令执行后,一般都有返回值,但是不同的命令的返回值是不一样的,最简单的返回如SET命令返回一个字符串,HSET命令会返回一个整数,而HGETALL会返回一个类似结构体的数据:
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
ctx := context.Background()
setCmd := rdb.Set(ctx, "test", "test_value", 0)
hSetCmd := rdb.HSet(ctx, "user:1", "id", 1, "name", "小张", "gender", "男")
hAllGetCmd := rdb.HGetAll(ctx, "user:1")
}在上面的代码中,我们可以看到在执行不同命令时,会返回不同cmd对象,比如Set()方法返回一个StatusCmd对象,HSet()方法返回IntCmd对象,而HGetAll()方法返回MapStringStringCmd对象。
有了cmd对象后,就可以获取命令执行结果及错误信息,有两种方法,一种是直接调用Result()方法返回结果与错误信息:
fmt.Println(setCmd.Result()) fmt.Println(hSetCmd.Result()) fmt.Println(hAllGetCmd.Result())
另一种方法是分开获得取结果和错误信息:
fmt.Println(setCmd.Val(),setCmd.Err()) fmt.Println(hSetCmd.Val(),hSetCmd.Err()) fmt.Println(hAllGetCmd.Val(),hAllGetCmd.Err())
上面两种输出方式输出的的结果都是:
OK <nil>
3 <nil>
map[gender:男 id:1 name:小张] <nil>
如果我们获得取一个不存在的key,此时命令会返回一个特殊的错误redis.Nil,这是一个特殊的错误,用于表示是否获得取了空值:
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("值是空字符串")
}执行尚未支持的命令
当然,有时候Redis新的版本可能会添加一些新的命令,而Go Redis还未提供支持,这时候可以调用Do方法来执行对应的命令,实际上Do()方法可以用于执行任何命令:
val, err := rdb.Do(ctx, "hgetall", "user:1").Result()
if err != nil {
if err == redis.Nil {
fmt.Println("key does not exists")
return
}
panic(err)
}
fmt.Println(val.(MapStringStringCmd))从上面的例子可以看出Do()执行不同的命令后返回值也是不同的。
结果集映射
有时候我们查询Redis后会返回多个key-value的结果集,比如mget、hget,hgetall这样的命令,Go redis提供了Scan()方法可以将查询回来的结果集扫描进对应的结构体当中:
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
type User struct {
ID int `redis:"id"`
Name string `redis:"name"`
Gender string `redis:"gender"`
}
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
ctx := context.Background()
var u User
err := rdb.HGetAll(ctx, "user:1").Scan(&u)
if err != nil {
panic(err)
}
fmt.Println(u)
}管道
管道(pipeline)允许在一次请求中发送多条Redis命令,并返回多个结果,这样可以节省一个一个执行命令需要付出的往返回时间:
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func main() {
opt := &redis.Options{
Addr: "localhost:6379",
}
rdb := redis.NewClient(opt)
ctx := context.Background()
cmds, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
pipe.Set(ctx, "test", "test_value", 0)
pipe.HSet(ctx, "user:1", "id", 1, "name", "小张", "gender", "男")
pipe.HGetAll(ctx, "user:1")
return nil
})
if err != nil {
panic(err)
}
for _, cmd := range cmds {
switch c := cmd.(type) {
case *redis.IntCmd:
fmt.Println(c.Val())
case *redis.StatusCmd:
fmt.Println(c.Val())
case *redis.MapStringStringCmd:
fmt.Println(c.Val())
}
}
}发布与订阅
Go Redis支持发布与订阅(Pub/Sub)。
发布消息
发布消息的方法为Publish:
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
ctx := context.Background()
//向渠道发送消息
err := rdb.Publish(ctx, "mychannel", "this is a message").Err()
if err != nil {
panic(err)
}
}订阅消息
订阅消息的方法为Subscribe,订阅之后通过返回的句柄调用ReceiveMessage()方法接收消息:
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
ctx := context.Background()
pubsub := rdb.Subscribe(ctx, "mychannel")
defer pubsub.Close()
//接收消息
for {
msg, err := pubsub.ReceiveMessage(ctx)
if err != nil {
panic(err)
}
fmt.Printf("从%s渠道接受到%s", msg.Channel, msg.Payload)
}
}小结
在本文中,我们讲解用github.com/redis/go-redis连接和操作Redis的基本操作,其实这个库支持很多高级的功能,比如哨兵,集群、分片等功能,以后在别的文章再讲解吧。
以上就是重学Go语言之如何使用Redis的详细内容,更多关于Go Redis的资料请关注好代码网其它相关文章!




