Go go-redis应用
go-redis是 Go 语言的一个流行的 Redis 客户端库,它提供了丰富的功能来与 Redis 数据库进行交互。
1、简单应用
package mainimport ("context""fmt""log""github.com/redis/go-redis/v9"
)func main() {ctx := context.Background()rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "", // no password setDB: 0, // use default DB})// 设置值err1 := rdb.Set(ctx, "your_key1", "your_value1", 0).Err()if err1 != nil {log.Fatalf("无法设置键值: %v", err1)}// 获取值val, _ := rdb.Get(ctx, "your_key1").Result()fmt.Println("your_key1: ", val)err2 := rdb.LPush(ctx, "your_key2", 111, 222, 333, "444").Err()if err2 != nil {log.Fatalf("无法推送到列表: %v", err2)}// 循环处理邮件队列for {// 从 Redis 队列中获取邮件email, err := rdb.RPop(ctx, "your_key2").Result()if err == redis.Nil {// 队列为空,退出循环fmt.Println("电子邮件队列为空。")break} else if err != nil {log.Fatalf("无法从队列中获取电子邮件: %v", err)} else {fmt.Println(email)}}
}
2、连接池管理
使用 go-redis 可以方便地管理 Redis 连接池,确保高效的连接复用。
package mainimport ("context""fmt""github.com/redis/go-redis/v9"
)func main() {var ctx = context.Background()// 创建一个新的 Redis 客户端client := redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "",DB: 0,PoolSize: 10, // 设置连接池大小})// 使用客户端pong, err := client.Ping(ctx).Result()if err != nil {panic(err)}fmt.Println(pong) // 输出 PONG
}
3、管道和事务
go-redis 支持管道(pipelines)和事务(transactions),可以批量执行命令,减少网络往返次数。
事务(Transactions)
事务在 Redis 中用来执行一系列命令,这些命令被打包在一起,然后一起执行。如果在执行过程中遇到错误,整个事务将被取消。事务可以保证操作的原子性。
package mainimport ("context""fmt""github.com/redis/go-redis/v9"
)func main() {var ctx = context.Background()// 创建 Redis 客户端client := redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "",DB: 0,})// 检查连接pong, err := client.Ping(ctx).Result()if err != nil {fmt.Printf("连接失败: %v", err)return}fmt.Printf("连接成功: %s\n", pong)key1 := "key1"key2 := "key2"// 使用 WATCH 命令监视键err = client.Watch(ctx, func(tx *redis.Tx) error {// 事务中的命令// SetNX函数:当该键不存在时才设置。如果键已经存在,命令将不执行任何操作。第三个参数为设置过期时间,0表示永不过期k1, err := tx.SetNX(ctx, key1, "value1", 0).Result() // 仅当 key1 不存在时设置值if err != nil {return err}if k1 {fmt.Println("key1 设置成功")} else {fmt.Println("key1 已存在,未进行设置操作")}k2, err := tx.SetNX(ctx, key2, "value2", 0).Result() // 仅当 key2 不存在时设置值if err != nil {return err}if k2 {fmt.Println("key2 设置成功")} else {fmt.Println("key2 已存在,未进行设置操作")}// 使用 MULTI 命令开始事务pipe := tx.Pipeline()// 将命令添加到事务队列_, err = pipe.Set(ctx, key1, "value1", 0).Result()if err != nil {return err}_, err = pipe.Set(ctx, key2, "value2", 0).Result()if err != nil {return err}// 使用 EXEC 命令执行事务_, err = pipe.Exec(ctx)if err != nil {return err}return nil}, key1, key2)if err != nil {if err == redis.TxFailedErr {fmt.Println("事务失败,可能因为键被其他客户端修改")} else {fmt.Printf("发生错误: %v", err)}return}// 如果事务成功,获取 key1 和 key2 的值val1, err := client.Get(ctx, key1).Result()if err != nil {fmt.Printf("获取 key1 失败: %v", err)return}val2, err := client.Get(ctx, key2).Result()if err != nil {fmt.Printf("获取 key2 失败: %v", err)return}fmt.Printf("key1: %s, key2: %s\n", val1, val2)
}
使用 Watch 方法监视了两个键 "key1" 和 "key2"。在 Watch 的回调函数中,我们尝试设置这两个键的值,如果设置成功,我们使用 Pipeline 方法将设置操作添加到事务队列中。最后,我们使用 Exec 方法提交事务。
请注意,如果 "key1" 或 "key2" 在我们设置它们之前已经被其他客户端设置,那么事务将不会执行,并且 Watch 方法将返回 redis.TxFailedErr 错误。在实际应用中,你可能需要根据这个错误来决定是否重试事务。
事务&管道
package mainimport ("context""fmt""github.com/redis/go-redis/v9"
)func main() {var ctx = context.Background()// 创建一个新的 Redis 客户端client := redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "",DB: 0,PoolSize: 10, // 设置连接池大小})// 假设我们想检查并更新的key以及期望的旧值和新值key := "mykey"oldValue := "expectedOldValue"newValue := "newValue"// 事务:使用 MULTI 和 EXEC 命令保证操作的原子性err := client.Watch(ctx, func(tx *redis.Tx) error {// 在事务中获取key的值val, err := tx.Get(ctx, key).Result()if err != nil && err != redis.Nil {return err}// 检查值是否与预期相符if val == oldValue {// 如果相符,尝试更新值_, err := tx.Set(ctx, key, newValue, 0).Result()if err != nil {return err}fmt.Println("更新成功")return nil} else {fmt.Println("键存在,值与预期值不匹配。")return nil // 这里返回nil表示不执行任何操作,事务会因为没有EXEC调用而自动取消}}, key)if err != nil {panic(err)}// 管道:批量发送命令cmds, err := client.Pipelined(ctx, func(pipe redis.Pipeliner) error {pipe.Set(ctx, "key1", "value1", 0)pipe.Get(ctx, "key1")return nil})if err != nil {panic(err)}fmt.Println(cmds) // 输出 [SetResult(string) <nil>, StringResult(value1, nil)]
}
4、发布/订阅模式
发布:
package mainimport ("context""fmt""github.com/redis/go-redis/v9""time"
)func main() {client := redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "",DB: 0,})ctx := context.Background()// 发送消息的循环for {err := client.Publish(ctx, "my_channel", "Hello, Redis!").Err()if err != nil {fmt.Printf("发布消息失败: %v\n", err)return}fmt.Println("消息发布成功")// 每5秒发布一条消息time.Sleep(5 * time.Second)}
}
订阅:
package mainimport ("context""fmt""github.com/redis/go-redis/v9""log""os""os/signal"
)func main() {// 创建 Redis 客户端client := redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "",DB: 0,})ctx := context.Background()// 订阅频道pubsub := client.Subscribe(ctx, "my_channel")// 处理接收到的消息go func() {defer func() {if err := pubsub.Close(); err != nil {log.Printf("关闭订阅失败: %v", err)}}()for {msg, err := pubsub.ReceiveMessage(ctx)if err != nil {log.Printf("接收消息失败: %v", err)return}fmt.Printf("接收到消息: %s\n", msg.Payload)}}()// 等待中断信号以退出sigChan := make(chan os.Signal, 1)signal.Notify(sigChan, os.Interrupt)<-sigChanfmt.Println("正在关闭订阅...")
}
package mainimport ("context""github.com/redis/go-redis/v9""log""os""os/signal""syscall""time"
)var ctx = context.Background()func main() {// 创建 Redis 客户端client := redis.NewClient(&redis.Options{Addr: "localhost:6379",Password: "",DB: 0,})if err := client.Ping(ctx).Err(); err != nil {log.Fatalf("无法连接到 Redis: %v", err)}// 启动订阅者go runSubscriber(client)// 发布者循环发送消息runPublisher(client)// 等待中断信号以优雅退出quit := make(chan os.Signal, 1)signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)<-quitlog.Println("接收到退出信号,正在关闭...")if err := client.Close(); err != nil {log.Fatalf("关闭 Redis 客户端失败: %v", err)}
}func runSubscriber(client *redis.Client) {pubsub := client.Subscribe(ctx, "my_channel")defer func() {if err := pubsub.Close(); err != nil {log.Printf("关闭订阅失败: %v", err)}}()log.Println("订阅者启动,正在监听消息...")for {msg, err := pubsub.ReceiveMessage(ctx)if err != nil {log.Printf("接收消息失败: %v", err)return}log.Printf("接收到消息: %s\n", msg.Payload)}
}func runPublisher(client *redis.Client) {ticker := time.NewTicker(5 * time.Second)defer ticker.Stop()log.Println("发布者启动,将定时发送消息...")for {select {case <-ticker.C:err := client.Publish(ctx, "my_channel", "Hello, Redis!").Err()if err != nil {log.Printf("发布消息失败: %v", err)return}log.Println("消息发布成功")}}
}
相关文章:
Go go-redis应用
go-redis 是 Go 语言的一个流行的 Redis 客户端库,它提供了丰富的功能来与 Redis 数据库进行交互。 1、简单应用 package mainimport ("context""fmt""log""github.com/redis/go-redis/v9" )func main() {ctx : context…...
从混乱到有序:PDM系统如何优化物料编码
在现代制造业中,物料管理是企业运营的核心。物料编码作为物料管理的基础,对于确保物料的准确性、唯一性和高效性至关重要。随着产品种类的不断增加和产品变型的多样化,传统的物料编码管理方式已经不能满足企业的需求。本文将探讨产品数据管理…...
npm发布自己的插件包
要发布自己的插件包到npm,可以按照以下步骤进行操作: 1.创建一个新项目 首先确保你已经安装了Node.js和npm。然后,在你的项目目录中初始化一个新的npm项目:npm init命令会引导你创建一个package.json文件,其中包含你插件包的基本…...
Pygame:新手指南与入门教程
在游戏开发领域,pygame 是一个广受欢迎的 Python 库,它提供了开发二维游戏的丰富工具和方法。这个库让开发者可以较少地关注底层图形处理细节,更多地专注于游戏逻辑和玩法的实现。本文将详细介绍 pygame,包括其安装过程、基本概念、主要功能和一个简单游戏的开发流程。 一…...
动态IP与静态IP的优缺点
在网络连接中,使用动态和静态 IP 地址取决于连接的性质和要求。静态 IP 地址通常更适合企业相关服务,而动态 IP 地址更适合家庭网络。让我们来看看动态 IP 与静态 IP 的优缺点。 1.静态IP的优点: 更好的 DNS 支持:静态 IP 地址在…...
上海市计算机学会竞赛平台2024年1月月赛丙组最大的和
题目描述 给定两个序列 𝑎1,𝑎2,…,𝑎𝑛a1,a2,…,an 与 𝑏1,𝑏2,…,𝑏𝑛b1,b2,…,bn,请从这两个序列中分别各找一个数,要求这两个数的差不超过给…...
C++三大特性之继承,详细介绍
阿尼亚全程陪伴大家学习~ 前言 每个程序员在开发新系统时,都希望能够利用已有的软件资源,以缩短开发周期,提高开发效率。 为了提高软件的可重用性(reusability),C提供了类的继承机制。 1.继承的概念 继承: 指在现有…...
Python推导式详解
引言 推导式(Comprehensions)是Python中一种简洁且强大的语法结构,可以用来生成列表、字典和集合。推导式使得代码更加简洁、易读,同时也更具Pythonic风格。今天我将将详细介绍列表推导式、字典推导式和集合推导式…...
stm32中如何实现EXTI线 0 ~ 15与对应IO口的配置呢?
STM32的EXTI控制器支持19 个外部中断/ 事件请求。每个中断设有状态位,每个中断/ 事件都有独立的触发和屏蔽设置。 STM32的19个外部中断对应着19路中断线,分别是EXTI_Line0-EXTI_Line18: 线0~15:对应外部 IO口的输入中断。 线16&…...
Python 短文本匹配,短文本语义相似度,基于大模型的短文本匹配,基于LLMs的短文本语义相似度识别,短文本语义扩充和匹配
1.任务描述 之前在做疾病相似度匹配的时候,堪称史诗级难题,虽然最后加上规则以及一些nlp模型,取得了差强人意的效果,但是短文本的语义相似度匹配一直属于比较难以攻克的难题 2.思路 随着近年大模型的飞速发展,就之前…...
提升接口性能方式汇总
1,sql 2,缓存,尤其面向用户,如app数据。可用redis咖啡,二级缓存。 充分利用redis,redis数据类型很多,平时场景中结合实际情况,找一下对应的redis实现方案 比如Zset可以排序&#…...
C++中的常见语法糖汇总
C中的语法糖是指使代码更简洁、可读性更高的语言特性和简化的语法。以下是一些常见的C语法糖: 1. 自动类型推导(auto) 使用 auto 关键字可以让编译器自动推导变量的类型,简化变量的声明。 auto x 10; // 编译器推导 x…...
TensorFlow Playground神经网络演示工具使用方法详解
在现代机器学习领域,神经网络无疑是一个重要的研究方向。然而,对于许多初学者来说,神经网络的概念和实际操作可能显得相当复杂。幸运的是,TensorFlow Playground 提供了一个交互式的在线工具,使得我们可以直观地理解和实验神经网络的基本原理。在这篇博客中,我们将详细介…...
【git】subtree 简单教程
git subtree使用案例 😄生命不息,写作不止 🔥 继续踏上学习之路,学之分享笔记 👊 总有一天我也能像各位大佬一样 🏆 博客首页 怒放吧德德 To记录领地 🌝分享学习心得,欢迎指正&am…...
C语言基础:字符串函数使用与剖析
strtok(分割字符串) char * strtok ( char * str, const char * sep ); sep参数是个字符串,定义了用作分隔符的字符集合 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标 记。strtok函数找…...
搭建Vulnhub靶机网络问题(获取不到IP)
搭建好靶场后,在攻击机运行arp-scan -l无法发现靶机IP。 这时候去看下靶机网络有没有问题。 重新启动客户机,一直按e进入安全模式(要是直接开机了就先按shift进入grub界面,再按e)找到ro,将ro改为rw signie…...
Prompt 提示词强大方法论和框架2
自从ChatGPT Chat Generative Pre-trained Transformer于2022年11月30日发布以来,一个新兴的行业突然兴起, 那就是提示工程Prompt engineering,可谓如日冲天。 从简单的文章扩写到RAG,ChatGPT展现了前所未有的惊人能力。 在上一…...
C语言分支和循环(2)
我的相关博客: C语言的分支与循环(1) 1.switch语句 除了 if 语句外,C语⾔还提供了 switch 语句来实现分⽀结构。 switch 语句是⼀种特殊形式的 的 if...else 结构,⽤于判断条件有多个结果的情况。它把多重 else if…...
14.FreeRTOS 流媒体缓存 Stream Buffer
FreeRTOS 中的 Stream Buffer(流媒体缓存) 在实时操作系统(RTOS)中,处理流媒体数据是一项非常关键的任务。FreeRTOS 提供了一种名为 Stream Buffer(流媒体缓存)的机制,用于高效地管…...
利用ffmpeg把视频分解成图片(每秒x张图)再图片合成视频
1. 视频分解成图片 ffmpeg -i rawVideo.mp4 -r 5 -f image2 img/%04d.png-i rawVideo.mp4 输入文件 -r 5 每秒5帧(1秒5张图) 可不写,默认每秒24帧 -f image2 表示输出的格式图像 可不写,默认图像 img/ 图片放在img文件夹下 %04d.png 图片的命名…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...
Canal环境搭建并实现和ES数据同步
作者:田超凡 日期:2025年6月7日 Canal安装,启动端口11111、8082: 安装canal-deployer服务端: https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...
