Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go Redis

重学Go语言之如何使用Redis

作者:程序员读书

Redis是我们开发应用程序中很常用的NoSQL数据库,那么在Go语言中要如何连接和操作Redis呢,在这篇文章中,我们就来一起来探究一下吧

Redis是我们开发应用程序中很常用的NoSQL数据库,作为一款内存数据库,Redis也支持数据持久化(RDBAOF两种机制),所以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安装

通过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.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.OptionsAddr字段:

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命令对应的方法为SetHGET对应的方法为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的结果集,比如mgethgethgetall这样的命令,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的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文