Redis - go

Redis - go

请求回应模式

在这里插入图片描述
redis 与 client 之间采用请求回应模式,一个请求包对应一个回应包;但是也有例外,pub/sub 模式下,client 发送 subscribe 命令并收到回应包后,之后被动接收 redis 的发布包;所以若需要使用 pub/sub 模式,那么需要在 client 下创建额外一条连接与 redis 交互;
在Redis中,客户端发送请求给服务器,然后服务器回应请求。在Go中,我们使用 Do 方法发送请求并接收响应。如果只有一个返回值,可以直接处理;如果有多个返回值,可以使用 redis.Values 来接收并处理。

Redis 协议图

在这里插入图片描述
redis 协议采用特殊字符(\r\n )来分割有意义的数据,redis 使用的是二进制安全字符串(用长度来标识字符串的长度),所以 redis 可以用来存储二进制数据(比如经过压缩算法加密的数据);
由于 Redis 的字符串结构是二进制安全的,这意味着它们可以存储任意的二进制数据,包括经过压缩或加密的数据。因此,Redis 可以用来存储和传输各种类型的二进制数据,如图像、视频、音频、压缩文件等。

# 存储压缩后的数据
SET compressed_data "压缩后的数据"

# 检索并解压数据
GET compressed_data
 set key val
 # "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\nval\r\n"

Redis 协议的序列化表示形式,它表示一个 SET 命令和对应的参数。

让我们解析一下这个字符串:

*3\r\n:表示后续有 3 个元素(即命令和参数的数量)。
$3\r\nSET\r\n:表示第一个参数是一个长度为 3 的字符串,其值为 “SET”。
$3\r\nkey\r\n:表示第二个参数是一个长度为 3 的字符串,其值为 “key”。
$3\r\nval\r\n:表示第三个参数是一个长度为 3 的字符串,其值为 “val”。

Redigo

git 地址:
https://github.com/gomodule/redigo.git
文档地址:https://pkg.go.dev/github.com/garyburd/redigo@v1.6.2/redis
 golang 的 redis 驱动;实现了 go 应用程序与 redis 服务器通信的协议实现,同时实现了与 redis 
交互时的数据转换

命令执行

要在 Go 中执行 Redis 命令,您可以使用 github.com/gomodule/redigo/redis 包,这是一个流行的 Redis 客户端库。

func (c Conn) Do(commandName string, args ...interface{}) (reply interface{}, err error)

c:Conn 类型的接收器,表示与 Redis 服务器的连接。

commandName:要执行的 Redis 命令的名称,例如 “SET”、“GET”、“LPUSH” 等。

args …interface{}:可变参数列表,用于传递 Redis 命令的参数。参数类型为 interface{},因此您可以传递任何类型的参数,例如字符串、整数、数组等。

reply interface{}:命令执行后的返回值,其类型为 interface{},因此可以根据命令的不同进行类型断言来获取具体的返回值类型。

err error:执行命令过程中可能发生的错误。如果命令执行成功,则 err 为 nil;否则,它将包含一个描述错误原因的非空错误值。

使用 Do 方法时,您需要传递命令的名称以及对应的参数。根据命令的不同,参数的数量和类型也会有所变化。例如,执行 SET 命令时,需要传递键名和键值;执行 LPUSH 命令时,需要传递列表名和要推入列表的值等。

// 设置键值对
reply, err := conn.Do("SET", "foo", "bar")

// 获取键值对的值
value, err := redis.String(conn.Do("GET", "foo"))

// 将元素推入列表
reply, err := conn.Do("LPUSH", "mylist", "value1", "value2", "value3")

使用 github.com/gomodule/redigo/redis 包。下面是一个简单的示例,展示了如何连接到 Redis 服务器并执行一些基本的操作:

package main

import (
	"fmt"

	"github.com/gomodule/redigo/redis"
)

func main() {
	// 连接到 Redis 服务器
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		fmt.Println("Failed to connect to Redis:", err)
		return
	}
	defer conn.Close()

	// 设置键值对
	_, err = conn.Do("SET", "foo", "bar")
	if err != nil {
		fmt.Println("Failed to set key:", err)
		return
	}

	// 获取键值对的值
	value, err := redis.String(conn.Do("GET", "foo"))
	if err != nil {
		fmt.Println("Failed to get key:", err)
		return
	}

	fmt.Println("Value of 'foo':", value)
}

上述代码首先连接到本地运行的 Redis 服务器,然后设置了一个键值对 “foo”-“bar”,最后获取了键 “foo” 的值并将其打印输出。
可以根据需要执行其他 Redis 命令,只需使用 conn.Do 方法并传递命令名称及其参数即可。例如,要执行 LPUSH 命令将元素推入列表,可以这样做:

_, err = conn.Do("LPUSH", "mylist", "value1", "value2", "value3")
if err != nil {
    fmt.Println("Failed to push elements to list:", err)
    return
}

在Go语言中,[]byte 表示字节切片,用于存储二进制数据。而 tcp 则是传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
当通过 TCP 连接发送数据时,可以使用 []byte 来表示数据,并通过 TCP 传输字节流。下面是一个简单的示例,展示了如何在 Go 中使用 net 包与 TCP 连接交互:

package main

import (
	"fmt"
	"net"
)

func main() {
	// 连接到远程 TCP 服务器
	conn, err := net.Dial("tcp", "example.com:8080")
	if err != nil {
		fmt.Println("Failed to connect to server:", err)
		return
	}
	defer conn.Close()

	// 准备要发送的数据,使用 []byte 表示字节流
	data := []byte("Hello, server!")

	// 将数据通过 TCP 连接发送给服务器
	_, err = conn.Write(data)
	if err != nil {
		fmt.Println("Failed to send data:", err)
		return
	}

	fmt.Println("Data sent successfully!")
}

在上面的示例中,我们使用 net.Dial 方法连接到一个名为 “example.com” 的服务器的 8080 端口。然后,我们准备了一个字符串数据 “Hello, server!”,并将其转换为 []byte 类型的字节流。最后,我们使用连接的 Write 方法将数据发送给服务器。

参数类型转换

在Go语言中,与Redis交互时,不同的Go类型需要以特定的方式转换为Redis参数类型。以下是常见类型转换的示例:

  • 将字符串直接发送给Redis:
str := "hello"
// 直接将字符串转换为字节切片([]byte)发送
conn.Do("SET", "key", []byte(str))
// 或者直接将字符串发送
conn.Do("SET", "key", str)
  • 将整数类型转换为字符串后发送给Redis:
num := 42
// 使用strconv.FormatInt将整数转换为字符串后发送
conn.Do("SET", "key", strconv.FormatInt(int64(num), 10))
  • 将浮点数类型转换为字符串后发送给Redis:
f := 3.14
// 使用strconv.FormatFloat将浮点数转换为字符串后发送
conn.Do("SET", "key", strconv.FormatFloat(f, 'g', -1, 64))
  • 将布尔类型转换为字符串后发送给Redis:
b := true
// 使用条件语句将布尔值转换为字符串后发送
if b {
    conn.Do("SET", "key", "1")
} else {
    conn.Do("SET", "key", "0")
}
  • 发送空值或nil给Redis:
// 发送空字符串给Redis
conn.Do("SET", "key", "")
// 或者发送nil给Redis
conn.Do("SET", "key", nil)
  • 对于其他类型,可以使用fmt包的Fprint函数将其转换为字符串后发送给Redis:
// 使用fmt.Fprint将其他类型转换为字符串后发送
someValue := SomeType{}
conn.Do("SET", "key", fmt.Sprint(someValue))

返回值转换

在Go语言中,从Redis获取的不同类型的返回值需要以特定的方式转换为Go类型。以下是常见类型转换的示例:

  • 将错误转换为redis.Error类型:
// 从Redis获取返回值
reply, err := conn.Do("GET", "key")
if err != nil {
    // 错误处理
    if redisErr, ok := err.(redis.Error); ok {
        // 如果是redis.Error类型的错误,则进行处理
        fmt.Println("Redis error:", redisErr.Error())
    } else {
        // 否则打印普通错误信息
        fmt.Println("General error:", err.Error())
    }
}
  • 将整数值转换为int64类型:
// 从Redis获取返回值
reply, err := conn.Do("GET", "integerKey")
if err != nil {
    // 错误处理
}
// 将返回值转换为int64类型
intValue, _ := redis.Int64(reply, err)
  • 将简单字符串转换为字符串类型:
// 从Redis获取返回值
reply, err := conn.Do("GET", "stringKey")
if err != nil {
    // 错误处理
}
// 将返回值转换为字符串类型
stringValue, _ := redis.String(reply, err)
  • 将批量字符串转换为字节切片([]byte)类型:
// 从Redis获取返回值
reply, err := conn.Do("GET", "bulkStringKey")
if err != nil {
    // 错误处理
}
// 将返回值转换为字节切片([]byte)类型
byteValue, _ := redis.Bytes(reply, err)
  • 将数组转换为[]interface{}类型:
// 从Redis获取返回值
reply, err := conn.Do("LRANGE", "listKey", 0, -1)
if err != nil {
    // 错误处理
}
// 将返回值转换为[]interface{}类型
arrayValue, _ := redis.Values(reply, err)

参数处理

  • 对于单个字符串和字节切片([]byte)类型的参数,可以直接传递,不需要进行额外的处理。

例如:

conn.Do("SET", "key", "value")
conn.Do("SET", "key", []byte("value"))
  • 对于整数和浮点数类型的参数,需要先将其转换为字符串类型,然后再传递给 Redis。

例如:

num := 42
conn.Do("SET", "key", strconv.Itoa(num))

f := 3.14
conn.Do("SET", "key", strconv.FormatFloat(f, 'g', -1, 64))
  • 使用 redis.Args 类型可以更方便地处理多个参数。它提供了 Add 方法来添加单个元素,并提供了 AddFlat
    方法来处理结构体和 map 类型的参数。

例如:

args := redis.Args{}.Add("SET").Add("key").Add("value")
conn.Do(args...)

// 使用 AddFlat 添加结构体或 map 参数
type Person struct {
    Name string
    Age  int
}
p := Person{Name: "Alice", Age: 30}
args2 := redis.Args{}.AddFlat(p)
conn.Do(args2...)

返回值转换处理

  • 接收单个返回值:通常情况下,如果只有一个返回值,可以直接处理。

例如:

reply, err := conn.Do("GET", "key")
if err != nil {
    // 错误处理
}
  • 接收多个不同类型的返回值:如果返回值包含多个不同类型的数据,可以使用 redis.Values
    来接收并进行解析。然后根据具体的数据类型进行处理。

例如:

reply, err := redis.Values(conn.Do("HMGET", "user:1001", "name", "age", "email"))
if err != nil {
    // 错误处理
}

var name string
var age int
var email string
_, err := redis.Scan(reply, &name, &age, &email)
if err != nil {
    // 错误处理

}

  • 接收单个结构体:如果返回的数据可以直接映射到一个结构体,则可以使用 redis.ScanStruct 来解析。

例如:

type User struct {
    Name  string
    Age   int
    Email string
}

var user User
reply, err := redis.Values(conn.Do("HGETALL", "user:1001"))
if err != nil {
    // 错误处理
}

err := redis.ScanStruct(reply, &user)
if err != nil {
    // 错误处理
}
  • 接收多个结构体:如果需要接收多个结构体,则可以使用 redis.ScanSlice 来解析。

例如:

type User struct {
    Name  string
    Age   int
    Email string
}

var users []User
reply, err := redis.Values(conn.Do("ZRANGE", "users", 0, -1))
if err != nil {
    // 错误处理
}

for _, v := range reply {
    var user User
    err := redis.ScanStruct(v.([]interface{}), &user)
    if err != nil {
        // 错误处理
    }
    users = append(users, user)
}
  • 21
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值