go-redis的应用

go-redis的应用

前言感悟

笔者先是学习了redis的基础知识,然后再学习go-redis的,但是我搜寻了网络中的go-redis的教程,好像没有这么讲解。都是在使用,没有特别的讲解。

  • 是因为没有像go等语言系统那么有庞杂的知识库

  • 作为一个导入的包使用,就像go中的其他导入包一样,你懂怎么使用就行,了解基本用法,有需要再像官网查询。

    这里提供一下go redis中文官网Golang Redis客户端 (uptrace.dev)

再看一下官方文档的目录

image-20230928155706511

感觉是在简单进行存储的进阶版,需要对于安全等性能问题提出要求时,会使用,如哨兵等。


但是对于笔者而言,这些过于高端,我暂时还是先理清后端大项目的基本流程,如gin,gorm,现在的redis,后面的docker部署等。

安装下载go-redis包

如果自身没有redis的包,请先在终端运行命令下载

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

存储相关的简单操作

简单示例

func main() {
	//上下文
	ctx := context.Background()
	//设置key
	err := rds.Set(ctx, "greet", "hello world", 10*time.Second).Err()
	if err != nil {
		panic(err)
	}
	//用get获取数据
	val, err := rds.Get(ctx, "greet").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("greet is ", val)
	//利用命令获取数据
	result, err := rds.Do(ctx, "get", "greet").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("greet is ", result.(string))

}

确保你的redis服务器时打开的,不然会出现错误。

image-20230928160637822

不同类型下的操作

因为redis可以存储常见的string,hash,list,set,zset,还有新版本HyperLogLog 结构。所以下面分别介绍常见的类型相关的函数信息。有需要可以看笔者介绍redis的博客简单了解redis及其相关操作_法耶会输出的博客-CSDN博客

其实大多时根据redis命令来进行命名的,所以熟悉redis的人应该看函数名就能知道函数的作用。在go-redis中,只是函数内部参数改变,如果使用goland这种集成开发环境下,他会给予提示,所以看看理解就行。

string类型
  • set设置值

    //设置key
    err := rds.Set(ctx, "greet", "hello world", 10*time.Second).Err()
    
  • get获取值

    //用get获取数据
    val, err := rds.Get(ctx, "greet").Result()
    
  • GetSet设置key的值,并返回key的旧值

    //用getset来返回旧值
    oldVal, err := rds.GetSet(ctx, "greet", "hello,my lover").Result()
    fmt.Println("old greet is ", oldVal)
    

    image-20230928162602480

  • SetNx 不存在该键就设置该key对应的值

    image-20230928162756202

  • MSet,Mget–设置多个key,获取多个key对应的value。

//批量设置key的值
err := rdb . MSet(ctx, "key1""value1""key2""value2""key3""value3").Err()
//批量查询key的值
vals,err := rdb . MGet(ctx,"key1", "key2""key3") . Result()
  • del 删除
rds.Del(ctx,"greet")
其他类型

hash类型就是在常见string的命令上添加了H。就不一一介绍了。

接着介绍**list类型**

函数名参数作用描述
LPushkey string, values …string将一个或多个元素插入到列表的左侧。
RPushkey string, values …string将一个或多个元素插入到列表的右侧。
LPopkey string从列表的左侧弹出并返回一个元素。
RPopkey string从列表的右侧弹出并返回一个元素。
LRangekey string, start int64, stop int64获取列表中指定范围内的元素。
LLenkey string获取列表的长度(即元素个数)。
LTrimkey string, start int64, stop int64修剪列表,保留指定范围内的元素,移除其他元素。
LRemkey string, count int64, value string从列表中删除指定数量的匹配元素。
LIndexkey string, index int64获取列表中指定索引位置的元素。
LSetkey string, index int64, value string设置列表中指定索引位置的元素值。

set类型函数如下:

函数名参数作用描述
SAddkey string, members …string向集合中添加一个或多个成员。
SRemkey string, members …string从集合中移除一个或多个成员。
SCardkey string获取集合的基数(集合中成员的数量)。
SMemberskey string获取集合中的所有成员。
SIsMemberkey string, member string检查一个成员是否存在于集合中。
SRandMemberkey string, count int64从集合中随机获取指定数量的成员,可重复。
SPopkey string从集合中随机弹出并返回一个成员。
SInterkeys …string返回给定多个集合的交集。
SUnionkeys …string返回给定多个集合的并集。
SDiffkeys …string返回给定多个集合的差集。
SScankey string, cursor uint64, match string, count int64迭代遍历集合中的元素。

讲解一下SScan函数,使用该函数可以有效地遍历和处理大型集合中的元素,而无需一次性加载整个集合到内存中。这对于处理大规模的集合数据非常有用,同时也可以减轻Redis服务器的负载。

var cursor uint64 = 0
var count int64 = 10

for {
    results, nextCursor, err := client.SScan("myset", cursor, "", count).Result()
    if err != nil {
        // 处理错误
    }

    // 处理返回的元素 results

    // 更新游标
    cursor = nextCursor

    // 当游标为0时,表示遍历完成
    if cursor == 0 {
        break
    }
}

zset类型

函数名参数作用描述
ZAddkey string, members …*Z向有序集合中添加一个或多个成员。
ZRemkey string, members …interface{}从有序集合中移除一个或多个成员。
ZCardkey string获取有序集合的基数(集合中成员的数量)。
ZScorekey string, member string获取有序集合中指定成员的分值。
ZRangekey string, start int64, stop int64, withScores bool按照排名范围获取有序集合中的成员。
ZRevRangekey string, start int64, stop int64, withScores bool按照逆序排名范围获取有序集合中的成员。
ZRangeByScorekey string, opt *ZRangeBy按照分值范围获取有序集合中的成员。
ZRevRangeByScorekey string, opt *ZRangeBy按照逆序分值范围获取有序集合中的成员。
ZRankkey string, member string获取有序集合中指定成员的排名(按照分值从小到大的顺序)。
ZRevRankkey string, member string获取有序集合中指定成员的逆序排名(按照分值从大到小的顺序)。
ZIncrBykey string, increment float64, member string将有序集合中指定成员的分值增加指定的增量值。
ZCountkey string, min, max string统计有序集合中分值在指定范围内的成员数量。
ZRemRangeByRankkey string, start, stop int64移除有序集合中排名在指定范围内的成员。
ZRemRangeByScorekey string, min, max string移除有序集合中分值在指定范围内的成员。
ZScankey string, cursor uint64, match string, count int64迭代遍历有序集合中的元素。

发布订阅操作

以下是go-redis库中常见的用于实现Redis发布订阅(Pub/Sub)功能的函数名、参数和作用描述的Markdown表格:

函数名参数作用描述
Subscribechannels …string订阅一个或多个频道,接收对应频道的消息。
PSubscribepatterns …string订阅一个或多个匹配模式,接收匹配的频道的消息。
Unsubscribechannels …string取消订阅一个或多个频道,停止接收对应频道的消息。
PUnsubscribepatterns …string取消订阅一个或多个匹配模式,停止接收匹配的频道的消息。
Publishchannel string, message interface{}向指定频道发布一条消息。
Ping检查与Redis服务器的连接状态。

这些函数用于实现发布订阅模式,其中:

  • Subscribe函数用于订阅一个或多个频道,客户端会接收订阅的频道上发布的消息。
  • PSubscribe函数用于订阅一个或多个匹配模式,客户端会接收匹配的频道上发布的消息。
  • Unsubscribe函数用于取消订阅一个或多个频道,停止接收对应频道的消息。
  • PUnsubscribe函数用于取消订阅一个或多个匹配模式,停止接收匹配的频道的消息。
  • Publish函数用于向指定频道发布一条消息,订阅该频道的客户端会接收到该消息。
  • Ping函数用于检查与Redis服务器的连接状态。

下面讲解一个简单的Redis发布订阅的示例,通过使用SubscribePublish以及相应的接收消息的逻辑,实现了消息的发布和订阅功能。

1.订阅通道,并接受消息(receiver.go文件

func main() {
	ctx := context.Background()

	rds := redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379",
	})
	//先订阅该通道
	sub := rds.Subscribe(ctx, "channel1", "channel2")

	for {
		message, err := sub.ReceiveMessage(ctx)
		if err != nil {
			panic(err)
		}
		fmt.Printf("received message from %s,%s", message.Channel, message.Payload)
	}

}

2.另一个文件的发送消息(publisher.go文件

func init() {
	rds = redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:6379",
		Password: "",
		DB:       0,
	})
}

// 采用通道来发送消息
func main() {
	ctx := context.Background()
	//发送消息
	rds.Publish(ctx, "channel1", "hello,my lover!")
}

最后运行,可以看到在receiver.go文件终端出现

image-20230928214211228

注意 :订阅频道过多也可能会导致 Redis 服务器的性能下降,因此需要根据实际情况来设计订阅和发布系统,以保证系统的可扩展性和高性能。

事务处理

事务:一次性执行多行命令,当其中部分命令执行出现错误,不会造成其他命令的放弃执行。所以会造成事务不具备原子性(要么都执行,要么都不执行,不可再分

在go-redis中,如果想要事务不受其他客户端命令的打扰,可以采用TxPipeline方式,相较于pipeline这是提供了一种将多个 Redis 命令打包到一个事务中的方式。这样可以减少网络往返的次数,

func main() {
	rds = redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:6379",
		Password: "",
		DB:       0,
	})
	ctx := context.Background()

	pipe := rds.TxPipeline()

	pipe.Set(ctx, "Name", "crystal", 0)
	pipe.Get(ctx, "Name")
	pipe.SAdd(ctx, "dormitory 622", []string{"wst", "zjy", "fhy", "prl"})
	pipe.SMembers(ctx, "dormitory 622")

	//开始执行
	cmders, err := pipe.Exec(ctx)

	if err != nil {
		panic(err)
	}
	fmt.Println("Result of Name:", cmders[1].(*redis.StringCmd).Val())

	var strings []string
	strings = cmders[3].(*redis.StringSliceCmd).Val()
	for _, s := range strings {
		fmt.Println("Result of 622:", s)
	}

}

得到结果

image-20230930154756395

下面补充一下相关 cmders, err := pipe.Exec(ctx)得到的cmder[1]等的类型转换:

命令类型返回形式
*redis.StringCmd返回字符串结果如 GET、SET、HGET、HSET 等
*redis.BoolCmd返回布尔值结果EXISTS、SISMEMBER、DEL 等
*redis.FloatCmd返回浮点数结果,如 HINCRBYFLOAT、INCRBYFLOAT
*redis.StringSliceCmd返回字符串切片结果如 SMEMBERS、ZRANGE、LRANGE 等。
*redis.StringStringMapCmd返回字符串键值对结果如 HGETALL、CONFIG GET 等
*redis.DurationCmd返回时间间隔结果如 TTL、PTTL
*redis.Cmd通用返回类型,需手动转换结果

请注意,最后一行的 *redis.Cmd 是一个通用的返回类型,需要根据具体情况手动转换结果。这些类型只是 Go Redis 客户端库中的一些常见命令类型,实际上还有其他类型可用于处理特定的命令和结果类型。


结束:我觉得如果只是简单的使用redis,这跟上一篇我写的关于redis的介绍相同,几乎没啥区别,所以真正发挥作用,还是redis的进阶~

urationCmd | 返回时间间隔结果如 TTL、PTTL | |*redis.Cmd` | 通用返回类型,需手动转换结果 |

请注意,最后一行的 *redis.Cmd 是一个通用的返回类型,需要根据具体情况手动转换结果。这些类型只是 Go Redis 客户端库中的一些常见命令类型,实际上还有其他类型可用于处理特定的命令和结果类型。


结束:我觉得如果只是简单的使用redis,这跟上一篇我写的关于redis的介绍相同,几乎没啥区别,所以真正发挥作用,还是redis的进阶~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值