go-redis使用入门
mhr18 2024-11-24 18:59 23 浏览 0 评论
安装go-redis
//redis 6
go get github.com/go-redis/redis/v8
//redis 7
go get github.com/go-redis/redis/v9
初始化连接redis
func redisInit() {
//初始化redis,连接地址和端口,密码,数据库名称
rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "wmq12138",
DB: 0,
})
}
入门案例
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
var rdb *redis.Client
func main() {
redisInit()
//创建上下文
ctx := context.Background()
//set方法设置key和value,处理返回的错误,参数(上下文,key名,value值,过期时间)
err := rdb.Set(ctx, "goredistest", "test", 0).Err()
if err != nil {
fmt.Print(err)
return
}
//get方法获取value
val, err := rdb.Get(ctx, "goredistest").Result()
if err != nil {
fmt.Print(err)
return
}
//do方法使用原生命令,返回值是一个interface类型
result, err := rdb.Do(ctx, "get", "goredistest").Result()
if err != nil {
fmt.Print(err)
return
}
fmt.Println("get:", val)
fmt.Print("原生命令:", result.(string))
}
连接配置
redis.NewClient(&redis.Options{}),其中Options是连接的配置,是一个结构体类型,以下是配置选项和说明
type Options struct {
// 网络类型:[ tcp , unix ]
// 默认是 tcp
Network string
// host:port 地址
Addr string
// 要使用的 TLS 配置。 当设置 TLS 时将协商。
TLSConfig *tls.Config
//创建一个新的连接,优先于Newwork和Addr选项
Dialer func(ctx context.Context, network, addr string) (net.Conn, error)
// 新建一个redis连接的时候,会回调这个函数
OnConnect func(ctx context.Context, cn *Conn) error
// 当连接到使用 Redis ACL 系统的 Redis 6.0 或更高版本的实例时,
// 使用指定的 用户名 对当前连接进行身份验证 (ACL 列表中定义的连接之一)。
Username string
// 可选密码。
// 必须与 requirepass 服务器配置选项中指定的密码(如果连接到 Redis 5.0 或更低版本的实例)
// 或 连接到使用 Redis ACL 系统的 Redis 6.0 或更高版本的实例时的用户密码 匹配。
Password string
// 连接到服务器后要选择的数据库。
DB int
// ====== 重试、退避时间======
// 放弃前的最大重试次数。
// 默认是 3 次重试; -1(非 0)禁用重试。
MaxRetries int
// 每次重试之间的最小退避。
// 默认为 8 毫秒; -1 禁用退避。
MinRetryBackoff time.Duration
// 每次重试之间的最大退避。
// 默认为 512 毫秒; -1 禁用退避。
MaxRetryBackoff time.Duration
// ======连接超时、读超时、写超时======
// 建立新连接的拨号超时。
// 默认为 5 秒。
DialTimeout time.Duration
// 套接字读取超时。
// 如果达到,命令将失败并超时而不是阻塞。
// 使用值 -1 表示无超时,使用 0 表示默认值。
// 默认为 3 秒。
ReadTimeout time.Duration
// 套接字写入超时。
// 如果达到,命令将失败并超时而不是阻塞。
// 默认为 ReadTimeout。
WriteTimeout time.Duration
// 连接池的类型。
// FIFO 池为 true,LIFO 池为 false。
// 请注意,与 lifo 相比,fifo 的开销更高。
PoolFIFO bool
// 最大套接字连接数。
// 默认为每个可用 CPU 10 个连接,由 runtime.GOMAXPROCS 报告。
PoolSize int
// 建立新连接缓慢时有用的最小空闲连接数。
MinIdleConns int
// 客户端退出(关闭)连接的连接年龄。
// 默认是不关闭老化的连接。
MaxConnAge time.Duration
// 如果所有连接都忙,则客户端在返回错误之前等待连接的时间。
// 默认为 ReadTimeout + 1 秒。
PoolTimeout time.Duration
// 客户端关闭空闲连接的时间。
// 应该小于服务器的超时时间。
// 默认为 5 分钟。 -1 禁用空闲超时检查。
IdleTimeout time.Duration
// 空闲连接 reaper 进行空闲检查的频率。
// 默认为 1 分钟。 -1 禁用空闲连接reaper,
// 但如果设置了 IdleTimeout,空闲连接仍会被客户端丢弃。
IdleCheckFrequency time.Duration
// 在从节点上启用只读查询。
readOnly bool
// 用于实现断路器或速率限制器的限制器接口。
Limiter Limiter
}
基本使用
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"time"
)
var rdb *redis.Client //创建redis客户端实例
var ctx = context.Background() //创建上下文
string类型的操作方法
- Get
- Set
- GetSet
- SetNX
- MGset
- MSet
- Incr,IncrBy
- Decr,DecrBy
- Del
- Expire
Get 获取key的值,返回值:错误信息error和value
//get 方法 返回值和错误信息
func Get(k string) string {
str, err := rdb.Get(ctx, k).Result()
if err != nil {
fmt.Print(err)
}
fmt.Println("key", k, "的值:", str)
return str
}
Set 设置key和value,以及key的过期时间expiration 返回值:error
//set 方法
func Set(key string, val interface{}, expiration time.Duration) {
err := rdb.Set(ctx, key, val, expiration).Err()
if err != nil {
fmt.Print(err)
return
}
}
GetSet 设置一个key的值,并且返回这个key的旧值
func GetSet(k string, v interface{}) interface{} {
oldValue, err := rdb.GetSet(ctx, k, v).Result()
if err != nil {
fmt.Print(err)
}
fmt.Println("设置一个key的值,并返回这个key的旧值:", oldValue)
return oldValue
}
SetNX 如果key不存在,则设置这个key的值
func SetNx(k string, v interface{}, t time.Duration) {
err := rdb.SetNX(ctx, k, v, t)
if err != nil {
fmt.Print(err)
}
}
MGet 批量查询key的值
func MGet(k ...string) {
err := rdb.MGet(ctx, k...)
if err != nil {
fmt.Print(err)
}
}
MSet 批量设置key的值
//MSet 批量设置key的值
func MSet(values ...interface{}) {
rdb.MSet(ctx, values)
}
Del 删除单个或者多个key
//delOneKeys 删除单个key
func delOneKeys(k string) {
rdb.Del(ctx, k)
}
//delKeys 删除多个key
func delKeys(k ...string) {
rdb.Del(ctx, k...)
}
Expire 设置key的过期时间
func expire(k string, t time.Duration) {
rdb.Expire(ctx, k, t)
}
Incr针对一个key的数值进行递增操作
IncrBy指定每次递增多少 IncrByFloat 指定每次递增多少,跟IncrBy的区别是累加的是浮点数
//addVal 针对一个key的数值进行递增操作
func addVal(k string) {
// Incr函数每次加一
val, err := rdb.Incr(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("最新值", val)
// IncrBy函数,可以指定每次递增多少
valBy, err := rdb.IncrBy(ctx, "key", 2).Result()
if err != nil {
panic(err)
}
fmt.Println("最新值", valBy)
// IncrByFloat函数,可以指定每次递增多少,跟IncrBy的区别是累加的是浮点数
valFloat, err := rdb.IncrByFloat(ctx, "key1", 2.2).Result()
if err != nil {
panic(err)
}
fmt.Println("最新值", valFloat)
}
Decr 针对一个key的数值进行递减操作
func Decr() {
// Decr函数每次减一
val, err := rdb.Decr(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("最新值", val)
// DecrBy函数,可以指定每次递减多少
valBy, err := rdb.DecrBy(ctx, "key", 2).Result()
if err != nil {
panic(err)
}
fmt.Println("最新值", valBy)
}
Hash类型的操作方法
内部采用数组+链表结构,采用链地址法解决哈希冲突。
- 1. HSet
- 2. HGet
- 3. HGetAll
- 4. HIncrBy
- 5. HKeys
- 6. HLen
- 7. HMGet
- 8. HMSet
- 9. HSetNX
- 10. HDel
- 11. HExists
// HashMethods Hash 操作方法
func HashMethods() {
//● HSet
// user_1 是hash key,username 是字段名, zhangsan是字段值
rdb.HSet(ctx, "user_1", "username", "zhangsan", "f1", "f_v1")
//● 2. HGet 根据key和field字段,查询field字段的值
result, _ := rdb.HGet(ctx, "user_1", "username").Result()
fmt.Println(result)
//● 3. HGetAll 获取所有的字段和值
all, _ := rdb.HGetAll(ctx, "user_1").Result()
fmt.Println(all)
//● 4. HIncrBy 累加count字段的值,一次性累加2, user_1为hash key
count, err := rdb.HIncrBy(ctx, "user_1", "count", 2).Result()
fmt.Println(count, err)
//● 5. HKeys根据key返回所有的字段名
keys := rdb.HKeys(ctx, "user_1")
fmt.Println(keys)
//● 6. HLen根据key,查询hash的字段数量
i, err := rdb.HLen(ctx, "user_1").Result()
fmt.Println(i)
//● 7. HMGet根据key和多个字段名,批量查询多个hash字段值
b, err := rdb.HMGet(ctx, "user_1", "f1", "count").Result()
fmt.Println(b)
//● 8. HMSet根据key和多个字段名和字段值,批量设置hash字段值
// 初始化hash数据的多个字段值
data := make(map[string]interface{})
data["id"] = 1
data["username"] = "lisi"
// 一次性保存多个hash字段值
rdb.HMSet(ctx, "key", data).Err()
//● 9. HSetNX如果field字段不存在,则设置hash字段值
rdb.HSetNX(ctx, "user_1", "f2", "f2value")
//● 10. HDel根据key和字段名,删除hash字段,支持批量删除hash字段
// 删除一个字段id
rdb.HDel(ctx, "key", "id")
// 删除多个字段
rdb.HDel(ctx, "key", "id", "username")
//● 11. HExists检测hash字段名是否存在
err = rdb.HExists(ctx,"key", "id").Err()
if err != nil {
fmt.Println(err)
}
}
List的操作方法
- 1. LPush
- 2. LPushX
- 3. RPop
- 4. RPush
- 5. RPushX
- 6. LPop
- 7. LLen
- 8. LRange
- 9. LRem
- 10. LIndex
- 11. LInsert
//ListOperateMethods List操作方法
func ListOperateMethods() {
//● 1. LPush 添加到list的左侧,LPush支持一次插入一个或者任意个数据
rdb.LPush(ctx, "w1", "w2", "w3", "w4", "w")
//● 2. LPushX 跟LPush的区别是,仅当列表存在的时候才插入数据,用法完全一样。
rdb.LPushX(ctx, "w1", "w2", "w3", "w4", "w")
//● 3. RPop从列表的右边删除第一个数据,并返回删除的数据
rdb.RPop(ctx, "w1")
//● 4. RPush
rdb.RPush(ctx, "w1", "wmq", "wmq2")
//● 5. RPushX 跟RPush的区别是,仅当列表存在的时候才插入数据, 他们用法一样
rdb.RPushX(ctx, "w1", "wm3", "w3")
//● 6. LPop从列表左边删除第一个数据,并返回删除的数据
val, _ := rdb.LPop(ctx, "w1").Result()
fmt.Println(val)
//● 7. LLen返回列表的大小
lLen, _ := rdb.LLen(ctx, "w1").Result()
fmt.Println(lLen)
//● 8. LRange返回列表的一个范围内的数据,也可以返回全部数据
result, _ := rdb.LRange(ctx, "w1", 0, lLen).Result()
fmt.Println(result)
//● 9. LRem删除列表中的数据 从列表左边开始,删除100, 如果出现重复元素,仅删除1次,也就是删除第一个
dels, _ := rdb.LRem(ctx, "key", 1, "w1").Result()
fmt.Println(dels)
//● 10. LIndex
// 列表索引从0开始计算,这里返回第6个元素
val, _ = rdb.LIndex(ctx, "w1", 5).Result()
fmt.Println(val)
//● 11. LInsert// 在列表中5的前面插入4
//// before是之前的意思
insert := rdb.LInsert(ctx, "w1", "after", 1, 2)
fmt.Println(insert)
}
Set的操作方法
Set是无序且不会重复的字符串集合 set和list的区别是set不包含重复的元素
- 1. SAdd
- 2. SCard
- 3. SIsMember
- 4. SMembers
- 5. SRem
- 6. SPop,SPopN
// Set操作方法
func setOperateMethods() {
//● 1. SAdd
rdb.SAdd(ctx, "set_key", 100, 10, 32, 4, 100, 5)
//● 2. SCard
res, _ := rdb.SCard(ctx, "set_key").Result()
fmt.Println(res)
//● 3. SIsMember判断元素是否在集合中
result, _ := rdb.SIsMember(ctx, "set_key", 900).Result()
fmt.Println(result)
//● 4. SMembers 获取集合中所有的元素
strings, _ := rdb.SMembers(ctx, "set_key").Result()
fmt.Println(strings)
//● 5. SRem删除集合元素
i, _ := rdb.SRem(ctx, "set_key", 100, 4).Result()
fmt.Println("返回删除的个数", i)
//● 6. SPop,SPopN 随机返回集合中的元素,并且删除返回的元素
rdb.SPop(ctx, "set_key")
fmt.Println(rdb.SMembers(ctx, "set_key").Result())
// 随机返回集合中的一个元素,并且删除这个元素
val, _ := rdb.SPop(ctx,"key").Result()
fmt.Println(val)
// 随机返回集合中的5个元素,并且删除这些元素
vals, _ := rdb.SPopN(ctx,"key", 5).Result()
fmt.Println(vals)
}
sorted set操作方法
有序的,非重复的的字符串集合
- 1. ZAdd
- 2. ZCard
- 3. ZCount
- 4. ZIncrBy
- 5. ZRange,ZRevRange
- 6. ZRangeByScore
- 7. ZRevRangeByScore
- 8. ZRangeByScoreWithScores
- 9. ZRem
- 10. ZRemRangeByRank
- 11.ZRemRangeByScore
- 12. ZScore
- 13. ZRank
发布订阅
Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。
发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。
订阅者 subscriber
//subscriber 订阅者订阅channel1的消息
func subscriber() {
// 订阅channel1这个channel
sub := rdb.Subscribe(ctx, "channel1")
// sub.Channel() 返回go channel,可以循环读取redis服务器发过来的消息
for msg := range sub.Channel() {
// 打印收到的消息
fmt.Println( msg.Channel, msg.Payload)
fmt.Println()
}
//或者
for {
msg, err := sub.ReceiveMessage(ctx)
if err != nil {
fmt.Println(err)
}
fmt.Println(msg.Channel, msg.Payload)
}
}
发布者 publisher
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"strconv"
)
var rdb *redis.Client //创建redis客户端实例
var ctx = context.Background() //创建上下文
func main() {
//初始化redis,连接地址和端口,密码,数据库名称
rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
// 将"message"消息发送到channel1这个通道上
for i := 1; i <= 100; i++ {
fmt.Println(i)
str := strconv.Itoa(i) + ".message收到前端回答"
rdb.Publish(ctx, "channel1", str)
}
}
其他的一些方法
func cancelSub() {
// 订阅channel1这个channel
sub := rdb.Subscribe(ctx, "channel1")
// 取消订阅
sub.Unsubscribe(ctx, "channel1")
}
func querySubCount() {
// 查询channel_1通道的订阅者数量
chs, _ := rdb.PubSubNumSub(ctx, "channel_1").Result()
for ch, count := range chs {
fmt.Println(ch) // channel名字
fmt.Println(count) // channel的订阅者数量
}
}
事务操作
redis事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
TxPinline
//事务操作
//TxPinline
func Txline() {
// 开启一个TxPipeline事务
pipe := rdb.TxPipeline()
// 执行事务操作,可以通过pipe读写redis
incr := pipe.Incr(ctx,"tx_pipeline_counter")
pipe.Expire(ctx,"tx_pipeline_counter", time.Hour)
// 上面代码等同于执行下面redis命令
//
// MULTI
// INCR pipeline_counter
// EXPIRE pipeline_counts 3600
// EXEC
// 通过Exec函数提交redis事务
_, err := pipe.Exec(ctx)
// 提交事务后,我们可以查询事务操作的结果
// 前面执行Incr函数,在没有执行exec函数之前,实际上还没开始运行。
fmt.Println(incr.Val(), err)
}
watch
redis乐观锁支持,可以通过watch监听一些Key, 如果这些key的值没有被其他人改变的话,才可以提交事务
func watch() {
// 定义一个回调函数,用于处理事务逻辑
fn := func(tx *redis.Tx) error {
// 先查询下当前watch监听的key的值
v, err := tx.Get(ctx, "key").Int()
if err != nil && err != redis.Nil {
return err
}
// 这里可以处理业务
v++
// 如果key的值没有改变的话,Pipelined函数才会调用成功
_, err = tx.Pipelined(ctx, func(pipe redis.Pipeliner) error {
// 在这里给key设置最新值
pipe.Set(ctx, "key", v, 0)
return nil
})
return err
}
// 使用Watch监听一些Key, 同时绑定一个回调函数fn, 监听Key后的逻辑写在fn这个回调函数里面
// 如果想监听多个key,可以这么写:client.Watch(ctx,fn, "key1", "key2", "key3")
rdb.Watch(ctx, fn, "key")
}
- 上一篇:go语言redis数据库操作详解
- 下一篇:使用Go从零实现一个Redis
相关推荐
- 【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库
-
如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...
- Pure Storage推出统一数据管理云平台及新闪存阵列
-
PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...
- 对Java学习的10条建议(对java课程的建议)
-
不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...
- SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!
-
官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...
- JDK21有没有什么稳定、简单又强势的特性?
-
佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...
- 「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了
-
在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...
- Java面试题及答案最全总结(2025版)
-
大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...
- 数据库日常运维工作内容(数据库日常运维 工作内容)
-
#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...
- 分布式之系统底层原理(上)(底层分布式技术)
-
作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...
- oracle 死锁了怎么办?kill 进程 直接上干货
-
1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...
- SpringBoot 各种分页查询方式详解(全网最全)
-
一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...
- 《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略
-
《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...
- LoadRunner(loadrunner录制不到脚本)
-
一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...
- Redis数据类型介绍(redis 数据类型)
-
介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...
- RMAN备份监控及优化总结(rman备份原理)
-
今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)