1. 第三方库 go-redis

因为 Go 标准库中是没提供 redis 的库,所以我们选择用 go-redis 这个第三方库。源码地址为 https://github.com/go-redis/redis

在命令行中使用 go get 来安装

go get github.com/go-redis/redis

2. 初始化 Redis

在进行代码之前,需要先安装 redis,安装指导请参考:https://blog.csdn.net/wohu1104/article/details/86755570

通过 redis.NewClient 函数创建一个 Redis 客户端,并通过 redis.Options 配置 Redis 相关的属性,例如 Redis 服务器地址、数据库名、数据库密码等。

package main

import (
	"fmt"

	"github.com/go-redis/redis"
)

var client *redis.Client

func initClient() error {
	// 创建 redis 客户端
	client = redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
		PoolSize: 10, // 连接池的大小为 10
	})
	//defer client.Close()
	// 通过 cient.Ping() 来检查是否成功连接到了 redis 服务器
	pong, err := client.Ping().Result()
	fmt.Println("Redis Client: " + pong)
	return err
}
func main() {
	initClient()
}

3. 操作 String

Redisstring 比较常用的类型,所有键值均是字符串对象。

func operateString() {
	// 第三个参数是过期时间, 如果是0, 则表示没有过期时间.
	err := client.Set("name", "wohu", 0).Err()
	if err != nil {
		fmt.Printf("set name error: %v\n", err)
		return
	}
	err = client.Set("age", 20, 0).Err()
	if err != nil {
		fmt.Printf("set age error: %v\n", err)
		return
	}
	// 获取某值
	userName, err := client.Get("name").Result()
	if err != nil {
		fmt.Printf("get user_name error: %v\n", err)
		return
	}
	fmt.Println("get name", userName)
	userAge, err := client.Get("age").Result()
	if err != nil {
		fmt.Printf("get age error: %v\n", err)
		return
	}
	fmt.Println("get age", userAge)
}

查看 redis 并获取值,与代码执行一致。

ubuntu@wohu:/$ redis-cli
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> get name
"wohu"
127.0.0.1:6379> get age
"20"
127.0.0.1:6379> 

4. 操作 List

func operateList() {
	// 从列表的尾部进行添加
	err := client.RPush("message", "01").Err()
	if err != nil {
		fmt.Printf("rpush message error: %v\n", err)
		return
	}
	// 从列表的头部进行添加
	err = client.LPush("message", "02").Err()
	if err != nil {
		fmt.Printf("lpush message error: %v\n", err)
		return
	}

	// 从列表尾部弹出元素
	message, err := client.RPop("message").Result()
	if err != nil {
		fmt.Printf("rpop message error: %v\n", err)
		return
	}
	fmt.Println("rpop message: ", message)

	// 获取长度
	length, err := client.LLen("message").Result()
	if err != nil {
		fmt.Printf("llen message error: %v\n", err)
		return
	}
	fmt.Println("message length: ", length)
}

redis 查询结果:

127.0.0.1:6379> lrange message 0 -1
1) "02"
127.0.0.1:6379> 

5. 操作 set

这是一个没有无序数组且不能有重复,其叫无序集合:

func operateSet() {
	// 向 set_test 中添加元素
	client.SAdd("set_test", "name")
	client.SAdd("set_test", "age")
	client.SAdd("set_test", "gender")

	// 判断 name 是否在集合中
	isMember, err := client.SIsMember("set_test", "name").Result()
	if err != nil {
		fmt.Printf("sismember set_test error: %v\n", err)
		return
	}
	fmt.Println("sismember set_test:", isMember)

	// 获取集合 set_test 中所有的元素
	all, err := client.SMembers("set_test").Result()
	if err != nil {
		fmt.Printf("smembers set_test error: %v\n", err)
		return
	}
	fmt.Println("smembers set_test: ", all)
}
127.0.0.1:6379> smembers set_test
1) "name"
2) "age"
3) "gender"
127.0.0.1:6379> 

6. 操作 hset

func operateHash() {
	// 向 hash 类型添加元素
	client.HSet("student", "name", "jack")
	client.HSet("student", "age", 18)
	// 批量地向名称为 student 的 hash 中添加元素
	client.HMSet("user", map[string]interface{}{"id": 1, "time": "2020-03-31"})
	// 批量获取名为 student 的 hash 中的指定字段的值.
	fields, err := client.HMGet("student", "name", "age").Result()
	if err != nil {
		fmt.Printf("hmget user error: %v\n", err)
		return
	}
	fmt.Println("hmget user: ", fields)
	// 获取名为 student 的 hash 中的字段个数
	length, err := client.HLen("student").Result()
	if err != nil {
		fmt.Printf("hlen student error: %v\n", err)
		return
	}
	fmt.Println("hlen user: ", length)
}

参考:
https://github.com/go-redis/redis
https://gitbook.cn/books/5e7637996ba17a6d2c9a3352/index.html
https://github.com/fwhezfwhez/gitchat/tree/master/chat1-web%E5%90%8E%E7%AB%AF%E5%AE%9E%E6%88%98
https://github.com/go-redis/redis
https://redis.uptrace.dev/guide/#installation

7. 综合示例

安装

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

注意:v8 在导入路径中

代码实现

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {

	rdb := redis.NewClient(
		&redis.Options{
			Network:     "tcp",
			Addr:        "localhost:6379",
			Password:    "",              // no password set
			DB:          0,               // use default DB
			DialTimeout: 3 * time.Second, // no time unit = seconds
			ReadTimeout: 6 * time.Second,
			MaxRetries:  2,
		})

	err := rdb.Set(ctx, "key", "value", 0).Err()
	if err != nil {
		panic(err)
	}

	// 当服务器返回 nil 时, go-redis 返回 redis.Nil
	// BLPOP and ZSCORE 也都会返回 redis.Nil
	val, err := rdb.Get(ctx, "b").Result()
	switch {
	case err == redis.Nil:
		fmt.Println("key does not exist")
	case err != nil:
		fmt.Println("Get failed", err)
	case val == "":
		fmt.Println("value is empty")
	}
	fmt.Println("===", val)

	// or 可以保存该命令,以后再分别访问该值和错误
	ret := rdb.Get(ctx, "b")
	fmt.Println(ret.Val(), ret.Err())

	// 执行任意或者自定义命令
	v, 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(v.(string))

	// Do 返回一个 Cmd 结构,该结构有很多方法来处理 interface{} 值
	// 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()

	*/

	// 发布订阅模式
	// go-redis允许发布消息和订阅频道。它还能自动处理重新连接的问题。
	err = rdb.Publish(ctx, "mychannel1", "payload").Err()
	if err != nil {
		panic(err)
	}

	// There is no error because go-redis automatically reconnects on error.
	pubsub := rdb.Subscribe(ctx, "mychannel1")

	// Close the subscription when we are done.
	defer pubsub.Close()

	// To receive a message:
	for {
		msg, err := pubsub.ReceiveMessage(ctx)
		if err != nil {
			panic(err)
		}

		fmt.Println(msg.Channel, msg.Payload)
	}
	// But the simplest way is using a Go channel which is closed together with subscription:
	ch := pubsub.Channel()

	for msg := range ch {
		fmt.Println(msg.Channel, msg.Payload)
	}

	// SET key value EX 10 NX
	set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result()

	// SET key value keepttl NX
	set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result()

	// SORT list LIMIT 0 2 ASC
	vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result()

	// ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2
	vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{
		Min:    "-inf",
		Max:    "+inf",
		Offset: 0,
		Count:  2,
	}).Result()

	// ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM
	vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{
		Keys:    []string{"zset1", "zset2"},
		Weights: []int64{2, 3},
	}).Result()

	// EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello"
	vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result()

	// custom command
	res, err := rdb.Do(ctx, "set", "key", "value").Result()
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐