当前位置: 首页 > news >正文

go-redis 框架基本使用

文章目录

    • redis使用场景
    • 下载框架和连接redis
      • 1. 安装go-redis
      • 2. 连接redis
    • 字符串操作
    • 有序集合操作
    • 流水线
    • 事务
      • 1. 普通事务
      • 2. Watch

redis使用场景

  • 缓存系统,减轻主数据库(MySQL)的压力。
  • 计数场景,比如微博、抖音中的关注数和粉丝数。
  • 热门排行榜,需要排序的场景特别适合使用ZSET。
  • 利用 LIST 可以实现队列的功能。
  • 利用 HyperLogLog 统计UV、PV等数据。
  • 使用 geospatial index 进行地理位置相关查询。

下载框架和连接redis

Go 社区中目前有很多成熟的 redis client 库,比如redigo和go-redis,读者可以自行选择适合自己的库。本文章使用 go-redis 这个库来操作 Redis 数据库。

1. 安装go-redis

# redis 6
go get github.com/go-redis/redis/v8
# redis 7
go get github.com/go-redis/redis/v9

2. 连接redis

var Rdb *redis.Clientfunc Connect() {Rdb = redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "",DB:       0,PoolSize: 10,})
}

字符串操作

只要Redis命令足够熟悉,那么对于这个框架的API的学习基本就没有什么问题。由于Redis命令太多,在此只列出了字符串和有序集合这两种数据类型的操作示例。

func String() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()//set命令_, err := connect.Rdb.Set(ctx, "name", "bing", 0).Result()if err != nil {fmt.Println(err.Error())}name, err := connect.Rdb.Get(ctx, "name").Result()fmt.Println(name)//GetSet命令v1, _ := connect.Rdb.GetSet(ctx, "name", "xyz").Result()fmt.Println("旧值: " + v1) //bingname, err = connect.Rdb.Get(ctx, "name").Result()fmt.Println("新值: " + name) //xyz//MSet和MGet命令connect.Rdb.MSet(ctx, "age", 18, "password", "1234")v2 := connect.Rdb.MGet(ctx, "name", "age", "password").Val()for _, v := range v2 {fmt.Println(v)}//IncrBy命令v3 := connect.Rdb.IncrBy(ctx, "age", 2).Val() //20fmt.Println(v3)//append命令connect.Rdb.Append(ctx, "password", "abc")v4 := connect.Rdb.Get(ctx, "password").Val() //1234abcfmt.Println(v4)//SetRange命令connect.Rdb.SetRange(ctx, "password", 0, "987654")v5 := connect.Rdb.Get(ctx, "password").Val() //987654cfmt.Println(v5)//GetRange命令v6 := connect.Rdb.GetRange(ctx, "password", 4, -1).Val() //54cfmt.Println(v6)v7 := connect.Rdb.Get(ctx, "password").Val() //987654cfmt.Println(v7)//StrLen命令v8 := connect.Rdb.StrLen(ctx, "name").Val() //3fmt.Println(v8)//获取编码方式v9 := connect.Rdb.ObjectEncoding(ctx, "age").Val() //intfmt.Println(v9)//redis.Nil的用法v10, err := connect.Rdb.Get(ctx, "no_existing").Result()if redis.Nil == err {fmt.Println("key不存在")} else if err != nil {fmt.Println(err.Error())} else {fmt.Println(v10)}
}

有序集合操作

func ZSet() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()ZSetKey := "languages"languages := []redis.Z{{Score: 90, Member: "Go"},{Score: 85, Member: "Python"},{Score: 99, Member: "C"},{Score: 95, Member: "Java"},{Score: 99, Member: "Rust"},{Score: 80, Member: "PHP"},}err := connect.Rdb.ZAdd(ctx, ZSetKey, languages...).Err()if err != nil {fmt.Println(err.Error())}//按照分数从低到高遍历v1 := connect.Rdb.ZRange(ctx, ZSetKey, 0, -1).Val()fmt.Println(v1) //[PHP Python Go Java C Rust]v2 := connect.Rdb.ZRangeWithScores(ctx, ZSetKey, 0, -1).Val()fmt.Println(v2) //[{80 PHP} {85 Python} {90 Go} {95 Java} {99 C} {99 Rust}]opt1 := &redis.ZRangeBy{Min:    "0",  //查询的最小分数值Max:    "95", //查询的最大分数值Offset: 0,    //查询的起始位置Count:  6,    //需要查询的元素个数}v3 := connect.Rdb.ZRangeByScoreWithScores(ctx, ZSetKey, opt1).Val()fmt.Println(v3) //[{80 PHP} {85 Python} {90 Go} {95 Java}]opt2 := &redis.ZRangeBy{Min:    "[K", //查询的最小字典序值Max:    "[X", //查询的最大字典序值Offset: 0,    //查询的起始位置Count:  5,    //需要查询的元素个数}v4 := connect.Rdb.ZRangeByLex(ctx, ZSetKey, opt2).Val()fmt.Println(v4) //[PHP Python Go Java C]v5 := connect.Rdb.ZCard(ctx, ZSetKey).Val()fmt.Println("集合长度: " + strconv.FormatInt(v5, 10)) // 6
}

流水线

使用流水线就是将多个执行的命令放入 pipeline 中,然后使用1次读写操作就像执行单个命令一样执行它们,就相当于把多个命令打包,然后一起发送给redis服务器,让redis服务器一次性执行完毕。这样做的好处是节省了执行命令的网络往返时间(RTT)。

注意:如果redis采用了分布式集群模式,不可以直接使用pipeline命令进行操作,因为访问的key可能并不在同一个节点上。

下面的示例代码中演示了使用 pipeline 将pipeline_counter键的值加1和设置过期时间。

func PipeLine() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()//创建一个Pipeline对象:pipepipe := connect.Rdb.Pipeline()//将名为"pipeline_counter"的键的值加1incr := pipe.Incr(ctx, "pipeline_counter")//设置"pipeline_counter"键的过期时间为1分钟pipe.Expire(ctx, "pipeline_counter", time.Minute)//执行所有的命令。_, err := pipe.Exec(ctx)if err != nil {panic(err)}// 在执行pipe.Exec之后才能获取到结果fmt.Println(incr.Val())
}

上面的代码相当于将以下两个redis命令一次发给 Redis Server 端执行,与不使用 Pipeline 相比能减少一次RTT。

INCR pipeline_counter
EXPIRE pipeline_counts 60

或者,你也可以使用Pipelined 方法,它会在当前函数退出时调用 Exec。

func PipeLine() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()var incr *redis.IntCmdcmdS, err := connect.Rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {incr = pipe.Incr(ctx, "pipelined_counter")pipe.Expire(ctx, "pipelined_counter", time.Minute)return nil})if err != nil {panic(err)}// 在pipeline执行后获取到结果fmt.Println(incr.Val())//使用类型断言特性来对 cmd 进行类型检查for _, cmd := range cmdS {switch v := cmd.(type) {case *redis.StringCmd:fmt.Println(v.Val())case *redis.IntCmd:fmt.Println(v.Val())case *redis.BoolCmd:fmt.Println(v.Val())default:fmt.Printf("unexpected type %T\n", v)}}
}

运行结果如下:

image-20230919111235190

所以,在那些我们需要一次性执行多个命令的场景下,就可以考虑使用 pipeline 来优化。

事务

1. 普通事务

Redis 是单线程执行命令的,因此单个命令始终是原子的,但是来自不同客户端的两个给定命令可以依次执行,例如在它们之间交替执行。使用事务后,Redis会按照命令的顺序执行这些命令,并且在执行过程中不会立即返回结果,只有在所有命令都执行完毕后,才会一次性返回所有命令的执行结果。也就是在执行过程中保证了原子性,即要么所有命令都执行成功,要么所有命令都不执行。

同时,Redis事务还支持WATCH命令,可以在事务执行之前监视一个或多个键,如果在事务执行期间这些键发生了改变,事务会被中断。这样可以确保在执行事务期间,被监视的键没有被其他客户端修改。

"Tx"是"Transaction"的缩写,意为"事务”。TxPipeline 和 TxPipelined 的使用方法如下所示:

func Work() {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()pipe := connect.Rdb.TxPipeline()incr := pipe.Incr(ctx, "tx_pipeline_counter")pipe.Expire(ctx, "tx_pipeline_counter", time.Minute)_, err := pipe.Exec(ctx)fmt.Println(incr.Val(), err)var incr2 *redis.IntCmd_, err = connect.Rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error {incr2 = pipe.Incr(ctx, "tx_pipeline_counter")pipe.Expire(ctx, "tx_pipeline_counter", time.Minute)return nil})fmt.Println(incr2.Val(), err)
}

运行结果如下:

image-20230919140331961

2. Watch

我们通常搭配 WATCH命令来执行事务操作。从使用WATCH命令监视某个 key 开始,直到执行EXEC命令的这段时间里,如果有其他用户抢先对被监视的 key 进行了替换、更新、删除等操作,那么当用户尝试执行EXEC的时候,事务将失败并返回一个错误,用户可以根据这个错误选择重试事务或者放弃事务。

Watch方法接收一个函数和一个或多个key作为参数。

Watch(fn func(*Tx) error, keys ...string) error

假设我们有一个应用程序,它需要保持用户的积分。我们需要一个函数,可以安全地减少用户的积分。为了避免并发问题,我们将使用WATCH命令来监视用户的积分,并在事务中更新积分。

func WatchUserPoints(userID string, points int) error {ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()for {// 监控err := connect.Rdb.Watch(ctx, func(tx *redis.Tx) error {// 得到当前用户的积分nn, err := tx.Get(ctx, userID).Int()//扣除积分时开启事务,points表示要扣除的积分_, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {err := pipe.Set(ctx, userID, n-points, 0).Err()return err})return err}, userID) //监控的键为userID,也就是当这个键的值(积分)如果在事务执行过程中被其他客户端修改,那么当前事务就会执行失败。//对错误的判断if err == redis.TxFailedErr {//表示监视的键在事务执行过程中被其他客户端修改了,因此事务执行失败了。continue} else if err != nil {//其他类型的错误return err} else {//没有错误break}}//能够跳出循环说明一切正常return nil
}

这段代码的目的是监视用户的当前积分,如果在事务执行过程中,其他客户端改变了这个键的值(也就是用户的积分),那么 Watch 会发现这个变化并使得事务失败,返回 redis.TxFailedErr 错误。

总的来说,这段代码的目的是确保在减少用户积分的过程中,用户的积分没有被其他客户端修改。这是通过Redis的 WATCH 命令来实现的,这个命令可以将一个或多个键标记为监视,然后在执行事务之前检查这些键是否已经被修改。

相关文章:

go-redis 框架基本使用

文章目录 redis使用场景下载框架和连接redis1. 安装go-redis2. 连接redis 字符串操作有序集合操作流水线事务1. 普通事务2. Watch redis使用场景 缓存系统,减轻主数据库(MySQL)的压力。计数场景,比如微博、抖音中的关注数和粉丝数…...

java内嵌浏览器CEF-JAVA、jcef、java chrome

java内嵌浏览器CEF-JAVA、jcef、java chrome jcef是老牌cef的chrome内嵌方案,可以进行java-chrome-h5-桌面开发,下面为最新版本(2023年9月22日10:33:07) JCEF(Java Chromium Embedded Framework)是一个基于…...

string类模拟实现——C++

一、构造与析构 1.构造函数 构造函数需要尽可能将成员在初始化列表中初始化,string类的成员这里自定义的和顺序表相似,有_str , _size , _capacity , 以及一个静态成员 npos ,构造函数这里实现两种,一种是传参为常量字符串的&am…...

在 SQL Server 中,可以使用加号运算符(+)来拼接字符串。但是,如果需要拼接多个字符串或表中的字段,就需要使用内置的拼接函数了

以下是 SQL Server 中的一些内置拼接函数: 1. CONCAT:将两个或多个字符串拼接在一起。语法为: CONCAT (string1, string2, ...)示例: SELECT CONCAT(Hello, , World) as combined_string;输出结果为:Hello World&a…...

蓝桥杯每日一题2023.9.25

4406. 积木画 - AcWing题库 题目描述 分析 在完成此问题前可以先引入一个新的问题 291. 蒙德里安的梦想 - AcWing题库 我们发现16的二进制是 10000 15的二进制是1111 故刚好我们可以从0枚举到1 << n(相当于二的n次方的二进制表示&#xff09; 注&#xff1a;奇数个0…...

前端面试的话术集锦第 20 篇博文——高频考点(输入 URL 到页面渲染的整个流程)

这是记录前端面试的话术集锦第二十篇博文——高频考点(输入 URL 到页面渲染的整个流程),我会不断更新该博文。❗❗❗ 借用这道经典面试题,将之前学习到的浏览器以及网络几章节的知识联系起来。 首先是DNS查询,如果这一步做了智能DNS解析的话,会提供访问速度最快的IP地址…...

Android Jetpack Compose之确定重组范围并优化重组

目录 1.概述2.确定Composable重组的范围3.优化重组的性能3.1 Composable 位置索引3.2 通过Key添加索引信息3.3 使用注解Stable优化重组 1.概述 前面的文章提到Compose的重组是智能的&#xff0c;Composable函数在进行重组时会尽可能的跳过不必要的重组&#xff0c;只对需要变化…...

【JDK 8-集合框架进阶】6.1 parallelStream 并行流

一、parallelStream 并行流 1.1 串行 和 并行的区别 > 执行结果 二、问题 2.1 paralleStream 并行是否一定比 Stream 串行快? 2.2 是否可以都用并行&#xff1f; > 报错 三、实战 > 执行结果 四、总结 一、parallelStream 并行流 多线程并发处理&#xff…...

C语言中结构体,枚举,联合相关介绍

本次重点&#xff1a; 1、结构体 &#xff1a; &#xff08;1&#xff09;结构体类型的声明 &#xff08;2&#xff09;结构的自引用 &#xff08;3&#xff09;结构体变量的定义和初始化 &#xff08;4&#xff09;结构体内存对齐 &#xff08;5&#xff09;结构体传参 …...

【干货】GNSS连续运行基准站网

文章目录 01 ​概述02 基准站建设03 数据中心04 数据通信网络 01 ​概述 1. 基准站网的组成 卫星连续运行基准站网&#xff08;Continuously Operating Reference Stations&#xff0c;缩写 CORS&#xff09;是由若干连续运行基准站及数据中心、数据通信网络组成的&#xff0…...

如何使用iPhone15在办公室观看家里电脑上的4k电影,实现公网访问本地群晖!

如何使用iPhone15在办公室观看家里电脑上的4k电影&#xff1f; 文章目录 如何使用iPhone15在办公室观看家里电脑上的4k电影&#xff1f;1.使用环境要求&#xff1a;2.下载群晖videostation&#xff1a;3.公网访问本地群晖videostation中的电影&#xff1a;4.公网条件下使用电脑…...

LeetCode之26.删除有序数组中的重复项和80.删除有序数组中的重复项II(C++)

文章目录 0 引言1 删除有序数组中的重复项1.1 解题方法1.2 C代码 2 删除有序数组中的重复项II2.1 解题方法2.2 C代码 0 引言 本文主要记录如何解决LeetCode中数组和字符串类别中的26.删除有序数组中的重复项&#xff08;简单&#xff09;及80.删除有序数组中的重复项II &#…...

linux驱动之input子系统简述

文章目录 一、什么是input子系统二、内核代码三、代码分析 一、什么是input子系统 Input驱动程序是linux输入设备的驱动程序&#xff0c;我们最常见的就按键&#xff0c;触摸&#xff0c;插拔耳机这些。其中事件设备驱动程序是目前通用的驱动程序&#xff0c;可支持键盘、鼠标…...

嵌入式裸机架构的探索与崩塌

为什么会想着探索下嵌入式裸机的架构呢&#xff1f;是因为最近写了一个项目&#xff0c;项目开发接近尾声时&#xff0c;发现了一些问题&#xff1a; 1、项目中&#xff0c;驱动层和应用层掺杂在一起&#xff0c;虽然大部分是应用层调用驱动层&#xff0c;但是也存在驱动层调用…...

MySQL高级语句(第二部分)

MySQL高级语句(第二部分)一、视图表 create view1、视图表概述2、视图表能否修改&#xff1f;&#xff08;面试题&#xff09;3、基本语法3.1 创建3.2 查看3.3 删除 4、通过视图表求无交集值 二、case语句三、空值(null) 和 无值(’ ) 的区别四、正则表达式五、存储过程1、简介…...

HTML计时事件(JavaScript)网页电子钟+网页计时器

setTimeout("函数","未来指定毫秒后调用函数"); clearTimeout(setTimeout("函数","未来指定毫秒后调用函数")); <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title>…...

使用群晖实现Videostation电影的大容量存储及分享教程

文章目录 1.使用环境要求2.制作视频分享链接3.制作永久固定视频分享链接 李哥和他的女朋友是一对甜蜜的情侣&#xff0c;但不幸的是&#xff0c;由于工作原因&#xff0c;他们目前分隔两地&#xff0c;无法常常亲密相伴。 这个距离让李哥特别怀念和女朋友一起在电影院观看电影的…...

后端大厂面试-15道题

1. 说说计算机存储结构 计算机存储结构通常包括这几个层次&#xff1a; 主存储器&#xff08;Main Memory&#xff09;&#xff1a;也称为内存&#xff08;RAM&#xff0c;Random Access Memory&#xff09;&#xff0c;主要用于存储当前正在执行的程序和数据。它是计算机中最…...

C++: 冒泡排序(Bubble Sort)

假设你有一列由数字组成的玻璃珠&#xff0c;这些珠子的重量不同&#xff0c;你希望将它们按照重量从轻到重排列。你会这样做&#xff1a; 从左到右&#xff0c;比较相邻的两颗珠子的重量。如果左边的珠子比右边的珠子重&#xff0c;就交换它们的位置。然后&#xff0c;继续向…...

跨域的解决方案

文章目录 概念一、什么是跨域问题二、为什么会发生跨域问题三、跨域解决方案1、JSONP2、添加响应头3、Spring注解CrossOrigin4、配置文件&#xff08;常用&#xff09;5、nginx跨域 概念 一、什么是跨域问题 前端调用的后端接口不属于同一个域&#xff08;域名或端口不同&…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...