Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Go语言Redis API基本功能实践

Go语言Redis API基本功能实践

作者头像
FunTester
发布于 2022-07-08 07:24:15
发布于 2022-07-08 07:24:15
73500
代码可运行
举报
文章被收录于专栏:FunTesterFunTester
运行总次数:0
代码可运行

本来想着放弃Go了,没想到人算不如天算,还是得继续Go的学习和练习。由于之前提到的原因,又要把Java版本操作Redis也要迁移到Go版本了。

学习路线如下:

  1. Redis连接和基本操作
  2. 集合操作:hash、list、set和有序集合
  3. Redis stream

在整个学习过程中也对比了一下Go和Java版本的Redis,也发现Go语言在使用上是非常简洁的,而且默认自带Redis连接池。

按照我的习惯,一般都会都原声的API进行封装,例如之前写到的Java版本Redis各类操作性能实践:FunTester框架Redis压测预备

由于Go已经解决了连接池的问题,封装主要解决的就是默认返回值和异常处理。还没在实际的工作中应用,只能先按照我写Java的经验来谢啦。目前还在学习Go语言简易线程池的问题以及Java的其他问题,再叠加最近工作的确比较忙,所以最近学得少,写的也少了。后续写完Go的Redis教程以后,我会针对这些Redis的API进行性能测试实践分享。

依赖

Go的依赖相对简单,我使用的go.mod的方式,也可以通过将依赖下载到本地的path中。

github.com/go-redis/redis v6.15.9+incompatible

Redis API封装

这里发现Go版本的Redis库相比Java版本都了几个批量操作的API,都是以M开头的,可能是因为使用场景并不多,所以写Java封装方法的时候也没注意,改天找找Java jedis的API。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package redis

import (
 "fmt"
 "funtester/base"
 "github.com/go-redis/redis"
 "log"
 "time"
)

//redis.Options 默认池大小为10×cpu核数

type RedisBase struct {
 Host string
 db   int
 pool *redis.Client
}

// init 初始化类,创建连接池
//  @Description:
//
func NewRdisPool(host string, db int) RedisBase {
 redisBase := RedisBase{Host: host, db: db}
 redisBase.pool = redis.NewClient(&redis.Options{
  //Password: "",
  Addr:            host,
  DB:              0,
  MaxRetries:      3,
  MinRetryBackoff: 100 * time.Millisecond,
  DialTimeout:     5 * time.Second,
  WriteTimeout:    1 * time.Second,
  PoolSize:        200,
  MaxConnAge:      10 * time.Second,
  IdleTimeout:     8 * time.Second,
 })
 _, err := redisBase.pool.Ping().Result()
 if err != nil {
  log.Fatal("连接失败", err)
 }
 log.Println("Redis 连接成功")
 ping := redisBase.Ping()
 if ping == "PONG" {
  log.Println("确认连接成功!")
 }
 return redisBase
}

func (r RedisBase) Ping() string {
 ping := r.pool.Ping()
 result, err := ping.Result()
 if err != nil {
  log.Println("确认连接失败")
 }
 return result
}

// Keys 获取所有的服务条件的keys列表
//  @Description:
//  @param patten
//  @return []string
//
func (r RedisBase) Keys(patten string) []string {
 result, err := r.pool.Keys(patten).Result()
 if err != nil {
  log.Printf("获取keys: %s 失败%s\n", patten, err.Error())
  return nil
 }
 return result
}

// Set 设置一个key的值
//  @Description:
//  @param key
//  @param value
//  @param expiration
//  @return string
//
func (r RedisBase) Set(key string, value interface{}, second time.Duration) string {
 result, err := r.pool.Set(key, value, time.Duration(second)*time.Second).Result()
 if err != nil {
  log.Printf("set:%s value: %s 失败\n", key, value)
  return base.Empty
 }
 return result
}

// Get 查询key的值
//  @Description:
//  @param key
//  @return string
//
func (r RedisBase) Get(key string) string {
 result, err := r.pool.Get(key).Result()
 if err != nil {
  log.Printf("get:%s 失败\n", key)
  return base.Empty
 }
 return result
}

// GetSet 设置一个key的值,并返回这个key的旧值
//  @Description:
//  @param key
//  @param value
//  @return string
//
func (r RedisBase) GetSet(key string, value interface{}) string {
 result, err := r.pool.GetSet(key, value).Result()
 if err != nil {
  log.Printf("set:%s value: %s 失败\n", key, value)
  return base.Empty
 }
 return result
}

// SetNX 如果key不存在,则设置这个key的值
//  @Description:
//  @param key
//  @param value
//  @param expiration
//  @return bool
//
func (r RedisBase) SetNX(key string, value interface{}, second int64) bool {
 result, err := r.pool.SetNX(key, value, time.Duration(second)*time.Second).Result()
 if err != nil {
  log.Printf("set:%s value: %s 失败\n", key, value)
  return false
 }
 return result
}

// MGet 批量查询key的值
//  @Description:
//  @param key
//  @param value
//  @param expiration
//  @return bool
//
func (r RedisBase) MGet(keys ...string) []interface{} {
 result, err := r.pool.MGet(keys...).Result()
 if err != nil {
  log.Printf("获取 keys : %s 失败 %s", fmt.Sprint(keys), err.Error())
  return nil
 }
 return result
}

// MSet 批量设置key的值
//  @Description:
//  @param keys
//  @return string
//
func (r RedisBase) MSet(keys ...string) string {
 result, err := r.pool.MSet(keys).Result()
 if err != nil {
  log.Printf("设置 keys : %s 失败 %s", fmt.Sprint(keys), err.Error())
  return base.Empty
 }
 return result
}

// Incr 针对一个key的数值进行递增操作
//  @Description:
//  @param key
//  @return string
//
func (r RedisBase) Incr(key string) int64 {
 result, err := r.pool.Incr(key).Result()
 if err != nil {
  log.Printf("自增 key: %s 失败 %s", key, err.Error())
  return base.TEST_ERROR
 }
 return result
}

// IncrBy 针对一个key的数值进行递增操作
//  @Description:
//  @param key
//  @param value
//  @return string
//
func (r RedisBase) IncrBy(key string, value int64) int64 {
 result, err := r.pool.IncrBy(key, value).Result()
 if err != nil {
  log.Printf("自增 key: %s 失败 %s", key, err.Error())
  return -1
 }
 return result
}

// Decr 针对一个key的数值进行递减操作
//  @Description:
//  @param key
//  @return string
//
func (r RedisBase) Decr(key string) int64 {
 result, err := r.pool.Decr(key).Result()
 if err != nil {
  log.Printf("自减 key: %s 失败 %s", key, err.Error())
  return base.TEST_ERROR
 }
 return result
}

// DecrBy 针对一个key的数值进行递减操作
//  @Description:
//  @param key
//  @param value
//  @return string
//
func (r RedisBase) DecrBy(key string, value int64) int64 {
 result, err := r.pool.DecrBy(key, value).Result()
 if err != nil {
  log.Printf("自减 key: %s 失败 %s", key, err.Error())
  return base.TEST_ERROR
 }
 return result
}

// Del 删除key操作,支持批量删除
//  @Description:
//  @param keys
//  @return int64
//
func (r RedisBase) Del(keys ...string) int64 {
 result, err := r.pool.Del(keys...).Result()
 if err != nil {
  log.Printf("删除 key: %s 失败 %s", fmt.Sprintln(keys), err.Error())
  return base.TEST_ERROR
 }
 return result
}

// Expire 设置key的过期时间,单位秒
//  @Description:
//  @param key
//  @param second
//  @return bool
//
func (r RedisBase) Expire(key string, second int64) bool {
 result, err := r.pool.Expire(key, time.Duration(second)*time.Second).Result()
 if err != nil {
  log.Printf("设置 key: %s 过期时间失败 %s", fmt.Sprintln(key), err.Error())
  return false
 }
 return result
}

API演示

基本上就是照着教程写完,然后再转成封装好的API实践,感觉更加清爽了,基本和Java版本的使用体验一致。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package test

import (
 "funtester/db/redis"
 "funtester/ftool"
 "github.com/go-playground/assert/v2"
 "log"
 "strconv"
 "testing"
)

var pool = redis.NewRdisPool("127.0.0.1:6379", 1)

func TestRedis(t *testing.T) {
 var str = "FunTester"
 set := pool.Set("fun", str, 0)
 log.Print(set)
 get := pool.Get("fun")
 assert.Equal(t, get, str)
 getSet := pool.GetSet("fun", str+ftool.RandomStr(3))
 log.Println(getSet)
 pool.Set("aa", "32342", 0)
 mGet := pool.MGet("fun", "aa")
 for i, i2 := range mGet {
  log.Printf("index :%d  value : %s\n", i, i2)
 }
 pool.Expire("fun", 300)
 keys := pool.Keys("fu*")
 for i, key := range keys {
  log.Printf("index : %d, key : %s", i, key)
 }
 key := str + strconv.Itoa(ftool.RandomInt(1000))
 pool.SetNX(key, "32432", 100)
 log.Println(pool.Get(key))
 log.Println("22222")
 i := pool.MGet(str, key)
 for _, i3 := range i {
  log.Println(i3)
 }
 pool.MSet("aa", "111", "aabbbb", "22222")
 pool.Incr("sum")
 pool.IncrBy("sum", 10)
 log.Println(pool.Get("sum"))
 strings := pool.Keys("aa*")
 for _, s := range strings {
  log.Println(s)
 }
 pool.Decr("aa")
 pool.Expire("sum", 100)
}

控制台输出

相对比较单调,只是确认一下实际效果,总体打印信息比较乱,不少方法不够熟练,各位将就看看。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
2022/06/18 21:31:06 Redis 连接成功
2022/06/18 21:31:06 确认连接成功!
=== RUN   TestRedis
2022/06/18 21:31:06 OK
2022/06/18 21:31:06 FunTester
2022/06/18 21:31:06 index :0  value : FunTesterc3F
2022/06/18 21:31:06 index :1  value : 32342
2022/06/18 21:31:06 index : 0, key : fun
2022/06/18 21:31:06 32432
2022/06/18 21:31:06 22222
2022/06/18 21:31:06 <nil>
2022/06/18 21:31:06 32432
2022/06/18 21:31:06 56
2022/06/18 21:31:06 aa
2022/06/18 21:31:06 aabbbb
2022/06/18 21:31:06 aaaa
--- PASS: TestRedis (0.00s)
PASS

BUG挖掘机·性能征服者·头顶锅盖

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Redis API——Set功能实践与性能测试【Go版】
之前说要写个 Go 语言版本的 Redis 操作 API 和性能测试的系列,没想到鸽了这么久才写了一半。实在实力不济,不仅需要多充充电,更需要结合实践,劳逸结合。首先来一个前文回顾:
FunTester
2022/12/09
3320
Redis API——List功能实践与性能测试【Go版】
前文提到Go语言Redis API基本功能实践,以及后续的学习实践计划,由于总总原因耽搁了许久。终究是计划赶不上变化,学完Go语言操作Redis的常用功能之后,我打算把API实践、封装、简单性能测试场景放在一起写。
FunTester
2022/12/09
4790
Go WebSocket + Redis 实现轻量级的订阅和实时消息推送
上一篇介绍了Golang中封装WebSocket功能,让WebSocket更简单好用和稳定。
杨永贞
2021/01/26
4.1K0
Go WebSocket + Redis 实现轻量级的订阅和实时消息推送
gin操作MySQL和Redis
go这些基础的东西,看起来很舒服,最起码对于写习惯java的人来讲,go真的很舒服,所以近一段时间可能一直连更,gin并没有直接封装操作MySQL的工具类,所以还是使用开源的工具
是小张啊喂
2021/08/10
2.8K0
嵌入式linux之go语言开发(八)存储模块的封装(二)
由于在终端上,不需要执行复杂的sql查询,多表级联查询等。就是用来存储记录的,因此设计为存储到表里的都为二进制的字节流。
杨永贞
2020/08/04
5090
machinery入门看这一篇(异步任务队列)
我们在使用某些APP时,登陆系统后一般会收到一封邮件或者一个短信提示我们在某个时间某某地点登陆了。而邮件或短信都是在我们已经登陆后才收到,这里就是采用的异步机制。大家有没有想过这里为什么没有使用同步机制实现呢?我们来分析一下。假设我们现在采用同步的方式实现,用户在登录时,首先会去检验一下账号密码是否正确,验证通过后去给用户发送登陆提示信息,假如在这一步出错了,那么就会导致用户登陆失败,这样是大大影响用户的体验感的,一个登陆提示的优先级别并不是很高,所以我们完全可以采用异步的机制实现,即使失败了也不会影响用户的体验。前面说了这么多,那么异步机制该怎么实现呢?对,没错,就是machinery框架,听说你们还不会使用它,今天我就写一个小例子,我们一起来学习一下他吧。
Golang梦工厂
2022/07/08
1.1K0
machinery入门看这一篇(异步任务队列)
3.Go语言项目操作Redis数据实践
快速了解 Redis 数据库 描述: Redis是一个开源的内存数据库, Redis提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上。除此之外,通过复制、持久化和客户端分片等特性,我们可以很方便地将Redis扩展成一个能够包含数百GB数据、每秒处理上百万次请求的系统。
全栈工程师修炼指南
2022/09/29
1.5K0
基于redisgo的redis客户端的封装示例
redisgo是一款go语言的redis客户端库。 为了简化对redis的操作,可以使用redisgo对redis常用命令进行封装。 首先在Github上面创建一个仓库redisgoExample 然后git clone将项目克隆到本地,比如说我的阿里云CentOS8服务器下,
ccf19881030
2021/01/02
2K0
gin学习——邮箱发送验证码注册用户
qq邮箱-设置-账户 安装 go get -u github.com/jordan-wright/email go get -u github.com/garyburd/redigo/redis dao/user_dao.go func SendEmailValidate(em []string) (string,error) { e:=email.NewEmail() e.From = fmt.Sprintf("发件人笔名 <发件人邮箱>") e.To = em // 生成
传说之下的花儿
2023/04/16
1.1K0
gin学习——邮箱发送验证码注册用户
Go语言中使用K8s API及一些常用API整理
在进入代码之前,理解k8s的go client项目是对我们又帮助的。它是k8s client中最古老的一个,因此具有很多特性。 Client-go 没有使用Swagger生成器,就像前面我们介绍的openAPI一样。它使用的是源于k8s项目中的源代码生成工具,这个工具的目的是要生成k8s风格的对象和序列化程序。 该项目是一组包的集合,该包能够满足从REST风格的原语到复杂client的不同的编程需求。
iginkgo18
2022/05/09
2.4K0
Go语言协程池实现
对于性能测试来讲,使用编程语言实现性能测试用例的核心就是并发编程,也就是同时执行多个测试用例,以模拟真实的负载情况。并发编程可以有效地提高测试效率,可以更快地发现系统中的瓶颈和性能问题。在实现并发编程时,需要考虑线程的同步和互斥,以确保测试结果的正确性和可靠性。此外,还需要考虑如何分配和管理资源,以避免资源竞争和浪费。
FunTester
2023/08/04
2050
Go语言协程池实现
用redis做一个简单的限流
最近项目中有个需求要实现限制某个用户在2个小时内只能访问3次的效果,所以就简单地用redis实现了一个限流方案。
Johns
2021/08/23
1.3K0
用redis做一个简单的限流
Go语言入门(十) Mysql与Redis操作
Mysql与Redis操作 Mysql开发 安装mysql,创建test库 创建表 mysql> CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT '', `age` int(11) DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; mysql> in
alexhuiwang
2020/09/24
9860
2种Go Redis客户端使用对比
从上图可以看出, go-redis虽然每次操作会比redigo慢10%左右, 但是redigo需要显示申请/关闭连接,所以总体上二者的性能差异其实不大
Johns
2022/07/25
6.1K0
go语言使用redis(redigo)
go的redis client用的比较多两个包是redix和redigo,因为beego cache模块里redis使用的是redigo,所以我也就使用这个包了。因为代码内容偏多,结构不清晰,不方便阅读,最后整理成一份思维导图,便于学习。当把整体分析,会发现提供给开发者使用的内容非常巧妙。
李海彬
2019/01/08
5.2K0
LevelDB 存储模块 Go 语言封装及高性能持久化队列实现
Leveldb是一个google实现的非常高效的kv数据库,能够支持billion级别的数据量。 在这个数量级别下还有着非常高的性能。
杨永贞
2021/04/12
1.7K0
我为什么放弃Go语言?
👉腾小云导读 你在什么时候会产生“想要放弃用 Go 语言”的念头?也许是在用 Go 开发过程中,接连不断踩坑的时候。本文作者提炼和总结《100 Go Mistakes and How to Avoid Them》里的精华内容,并结合自身的工作经验,盘点了 Go 的常见典型错误,撰写了这篇超全避坑指南。让我们跟随文章,一起重拾用 Go 的信心~ 👉目录 1 注意 shadow 变量 2 慎用 init 函数 3 embed types 优缺点 4 Functional Options Pattern 传递参数
腾讯云开发者
2023/06/06
1.7K0
我为什么放弃Go语言?
嵌入式linux之go语言开发(六)几行代码实现终端的远程日志诊断
以往设备有问题了,是如何诊断的?我们是现场人员到现场,又是配合抓包,又是配合提供机器日志,效率极其低下。
杨永贞
2020/08/04
4560
Go语言银联8583报文解析库,支持联小额免密付和银商聚合支付
最近整合了进了银联小额双免交易和银商的聚合支付交易通道,这可以是网上最简单的8583报文解析库了。
杨永贞
2021/03/05
1.6K0
Go(四)Redis还不会使用?
1、数据结构(3.2之前):sds:simple dynamic string是一个二进制安全数组 sds:
lomtom
2021/12/10
8440
Go(四)Redis还不会使用?
相关推荐
Redis API——Set功能实践与性能测试【Go版】
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验