redis在go语言中的使用
以下说明以读者有redis基础的前提下进行
未学习redis的可以到b站1小时浅学redis了解大概,学会如何使用
【GeekHour】一小时Redis教程_哔哩哔哩_bilibili
以下开发环境以windows为测试环境,旨在练习redis在go语言中的使用
redis使用的是5.0.14的windows版本(正常开发项目redis都是在linux上使用,windows的redis版本很低),但基础功能都有,满足学习要求;
下载链接:https://github.com/tporadowski/redis/releases
(官网是没有windows版本的)
下载完成后,打开黑窗口,输入redis-cli显示
即为成功,可以选择性下载redis的gui工具redisInsight,官网链接:
RedisInsight | The Best Redis GUI
使用时截图:
左侧会显示key,点击后右侧会显示value的值,使用和查找起来较为方便,能够增加学习效率,当然还有很多功能,这里就不赘述
1引入go-redis库
为什么使用这个库,而不是其他的库呢?
理由:
- 性能高效: Go-Redis实现了高性能的Redis客户端,具有低延迟和高吞吐量。它采用了异步的方式处理多个并发请求,从而提高了性能。
- 完整支持Redis功能: Go-Redis库提供了对Redis的全面支持,包括对基本数据结构(字符串、哈希、列表、集合等)的操作,事务,流水线(pipeline)等功能。
- 易用性: Go-Redis提供了简单而直观的API,易于使用。它封装了与Redis的底层通信细节,使得开发者可以专注于业务逻辑而不必过多关注底层实现。
- 连接池: Go-Redis包含了连接池的支持,这有助于有效地管理和复用与Redis的连接,减少了连接的创建和销毁开销,提高了性能。
- Active development和社区支持: Go-Redis是一个活跃的项目,有一个庞大的社区支持。这意味着它经常得到更新和改进,并且有丰富的文档和社区资源可供参考。
- 灵活性: Go-Redis允许开发者选择不同的执行模式,如同步、异步和流水线,以满足不同场景下的需求。
总之,这个库用的人多,并且功能齐全,很适合在go语言中与redis交互;(好用就完事了!!!)
2在go项目中的初始化
其实很简单,和mysql初始化优点相似;
为了方便学习,初始化都写在一个文件中
如下:
package main
import("fmt""github.com/go-redis/redis/v8""context")funcmain(){// 创建一个新的Redis客户端实例
client := redis.NewClient(&redis.Options{
Addr:"localhost:6379",// Redis服务器地址
Password:"",// 可选:如果有密码的话
DB:0,// 使用的数据库编号})// 使用Ping测试连接
pong, err := client.Ping(context.Background()).Result()if err !=nil{
fmt.Println("连接Redis出错:", err)return}
fmt.Println("连接成功,Ping结果:", pong)// 在程序结束时关闭连接defer client.Close()// 在这里可以继续执行其他与Redis相关的操作}
测试运行成功会输出:
连接成功,Ping结果: PONG
我们知道redis共有五大基本数据类型:string,hash,list,set,Sorted Set
- 字符串(String): 字符串是最基本的数据类型,可以包含任何数据,比如文本、数字等。在Redis中,字符串可以用于存储各种类型的数据,例如配置信息、计数器、缓存等。常用的字符串操作命令有
SET
、GET
、INCR
、DECR
等。 - 哈希(Hash): 哈希是一个键值对集合,每个键值对称为字段和值。哈希适用于存储对象,可以将一个对象存储在一个哈希中,然后通过字段来访问对象的各个属性。常用的哈希操作命令有
HSET
、HGET
、HMSET
、HGETALL
等。 - 列表(List): 列表是一个有序的字符串元素集合,可以在列表的两端执行添加和删除操作。列表适用于实现队列、栈等数据结构,也可以用于存储一系列有序的数据。常用的列表操作命令有
LPUSH
、RPUSH
、LPOP
、RPOP
等。 - 集合(Set): 集合是一组唯一的无序字符串元素的集合。集合适用于存储一组不重复的元素,可以执行交集、并集、差集等操作。常用的集合操作命令有
SADD
、SREM
、SISMEMBER
、SMEMBERS
等。 - 有序集合(Sorted Set): 有序集合是集合的一个扩展,其中每个成员都关联了一个分数,可以按照分数对成员进行排序。有序集合适用于实现排行榜、时间线等功能。常用的有序集合操作命令有
ZADD
、ZRANGE
、ZSCORE
、ZREMRANGEBYRANK
等。
在go-redis中也是如此,再加上发布订阅和事务处理基本就是要学习的go-redis知识了;
基础键值对相关操作 string
在go中简单设置键值对并查找键值对
简单设置一个键值对,来试试是否能够查找成功:
在go中设置key方法:Set
// 生成测试用的key
testKey :="test_key"// 设置key的值,演示Set方法
err = client.Set(context.Background(), testKey,"Hello, Redis!",0).Err()if err !=nil{
fmt.Println("设置key出错:", err)return}
fmt.Println("设置key成功")//解释://通过创建testKey变量,你定义了一个测试用的键。//使用client.Set方法设置了键test_key的值为字符串"Hello, Redis!",并指定了过期时间为0,表示不设置过期时间。//通过检查错误(err != nil)来确保设置操作是否成功。如果设置失败,你输出了错误信息;否则,你输出了"设置key成功"。
检测key对应的value的值的方法:Get
// 获取key的值,演示Get方法
value, err := client.Get(context.Background(), testKey).Result()//result作用是:等待并返回实际的 Redis 命令执行结果。 这种异步操作和等待结果的方式有助于确保代码在获取 Redis 操作结果时不会阻塞整个程序,以便更好地处理并发性能。if err !=nil{
fmt.Println("获取key出错:", err)return}
fmt.Printf("获取key的值:%s\n", value)}//成功运行时会返回://获取key的值:Hello, Redis!
redisInsight截图:
获取指定键的当前值并设置一个新的值:GetSet
// 使用 GETSET 获取testKey原有的值存入到oldValue中,并设置新值为NewValue
oldValue, err := client.GetSet(context.Background(), testKey,"NewValue").Result()if err !=nil{
fmt.Println("GETSET 操作出错:", err)return}
fmt.Printf("旧值:%s\n", oldValue)// 获取更新后testKey中的值并存到newValue中
newValue, err := client.Get(context.Background(), testKey).Result()if err !=nil{
fmt.Println("获取key出错:", err)return}
fmt.Printf("新值:%s\n", newValue)
其实还是很简单的,都是一些重复代码段;
批量设置key的值:MSet
// 准备要设置的键值对
keyValues :=map[string]interface{}{"key1":"value1","key2":"value2","key3":"value3",}// 使用 MSet 方法批量设置键值对
err = client.MSet(context.Background(), keyValues).Err()if err !=nil{
fmt.Println("批量设置键值对出错:", err)return}//这个M的意思其实是mutiple(多个),不止针对普通string,对于HGet等等都能变成HMGet,批量增加
成功
增加整数的值的两个方法:Incr,Incrby
前者可以将值每次增加1,当要增加的值不存在时,会先自动置为0进行操作。下例就是
// 示例使用的键名
key :="myKey"// 使用 INCR 递增键的值, myKey初值为空,自动置为0+1了
newValue, err := client.Incr(context.Background(), key).Result()if err !=nil{
fmt.Println("INCR 操作出错:", err)return}
fmt.Printf("INCR 后 %s 的值为 %d\n", key, newValue)// 使用 INCRBY 指定增量递增键的值 1+5=6;
increment :=5
newValue, err = client.IncrBy(context.Background(), key,int64(increment)).Result()if err !=nil{
fmt.Println("INCRBY 操作出错:", err)return}
fmt.Printf("INCRBY %d 后 %s 的值为 %d\n", increment, key, newValue)
在实际开发中还是要看需要什么用什么
设置过期时间
之前的Set方法中,最后一个参数是0,表示的就是过期时间设置,默认以秒为单位,当为0时,表示永不过期,写10,就是10s后过期,写其他单位的数字就需要加单位,如1*time.Minute就是1分钟;
而正规一点的过期时间设置方法是:
使用Expire方法:直接设置key在生成后多少时间过期,比如10秒后过期
// 设置 key 的值
err := client.Set(context.Background(),"myKey","myValue",0).Err()if err !=nil{
fmt.Println("设置 key 的值出错:", err)return}// 给 key 设置过期时间为 10 秒
err = client.Expire(context.Background(),"myKey",10*time.Second).Err()if err !=nil{
fmt.Println("给 key 设置过期时间出错:", err)return}
使用ExpireAt方法:表示过期的具体时间点,比如直接写成25年的1月1号0点0分过期;
// 设置 key 的值
err := client.Set(context.Background(),"myKey","myValue",0).Err()if err !=nil{
fmt.Println("设置 key 的值出错:", err)return}// 给 key 设置过期时间为 10 秒后的某个特定时间
expirationTime := time.Now().Add(10* time.Second)
err = client.ExpireAt(context.Background(),"myKey", expirationTime).Err()if err !=nil{
fmt.Println("给 key 设置过期时间出错:", err)return}
哈希键值对操作:
HGet
先举个例子方便理解,比如,原来的Get命令只能生成简单的键值对,但使用HGet,可以将多个键值对变成同一个哈希表对应的键值对,例如:
这样就清楚了吧,代码示例:
创建和获取哈希类型
// 准备哈希名、字段和值
hashName :="user:1"
fieldName :="username"
fieldValue :="JohnDoe"// 使用 HSet 方法设置哈希字段的值
err := client.HSet(context.Background(), hashName, fieldName, fieldValue).Err()if err !=nil{
fmt.Println("设置哈希字段的值出错:", err)return}// 使用 HGet 方法获取哈希字段的值
result, err := client.HGet(context.Background(), hashName, fieldName).Result()if err !=nil{
fmt.Println("获取哈希字段的值出错:", err)return}
批量创建哈希类型中的键值对
一看就会
// 准备哈希名
hashName :="user:1"// 使用 HMSet 一次性设置多个键值对
keyValueMap :=map[string]interface{}{"username":"JohnDoe","email":"[email protected]","age":"30",}
err := client.HMSet(context.Background(), hashName, keyValueMap).Err()if err !=nil{
fmt.Println("一次性设置多个键值对出错:", err)return}
fmt.Printf("成功一次性设置多个键值对到哈希表 %s\n", hashName)}
到这里其实我们已经发现了,对于redis的操作基本都是相同的,只是调用函数和一两个参数的不同,最主要的还是学好redis基础,
哈希中使用Incr,Incrby增加值的大小
和string的很像,只是多了一个哈希的参数
// 哈希键名
hashKey :="myHash"// 哈希字段名
fieldName :="myField"// 使用Incr方法自增哈希中的字段值
result, err := client.HIncrBy(hashKey, fieldName,1).Result()if err !=nil{
fmt.Println("Error incrementing field:", err)return}
fmt.Printf("Incr Result: %d\n", result)// 使用IncrBy方法自定义增量自增哈希中的字段值
customIncrement :=5
result, err = client.HIncrBy(hashKey, fieldName,int64(customIncrement)).Result()if err !=nil{
fmt.Println("Error incrementing field:", err)return}
fmt.Printf("IncrBy Result: %d\n", result)
redis中的方法很多,之后就不一一展示了,只会挑选一些比较重要或者难以掌握的强调,毕竟有些简单操作真正使用时直接套代码就可以了;
Hkeys:获取指定哈希键名的哈希表中所有字段
// 哈希键名
hashKey :="myHash"// 使用HKeys方法获取哈希表中所有字段
fields, err := client.HKeys(hashKey).Result()if err !=nil{
fmt.Println("Error getting hash keys:", err)return}
HGetAll:返回哈希键中的所有字段及其对应的值
// 哈希键名
hashKey :="myHash"// 使用HGetAll方法获取哈希表中所有字段及其对应的值
fieldValues, err := client.HGetAll(hashKey).Result()if err !=nil{
fmt.Println("Error getting hash field values:", err)return}
fmt.Printf("Hash field values for %s: %v\n", hashKey, fieldValues)
HMGet同时设置多个哈希字段
// 哈希键名
hashKey :="myHash"// 使用HMSet方法设置多个哈希字段及其对应的值
fieldsAndValues :=map[string]interface{}{"field1":"value1","field2":"value2","field3":123,}
result, err := client.HMSet(hashKey, fieldsAndValues).Result()if err !=nil{
fmt.Println("Error setting hash fields:", err)return}
fmt.Printf("HMSet Result: %v\n", result)
HSetNX:用于在哈希表中设置字段的命令,但是只有在字段不存在时才会设置成功
// 哈希键名
hashKey :="myHash"
field :="myField"
value :="myValue"// 使用HSetNX方法设置哈希字段,只有在字段不存在时才会设置成功
result, err := client.HSetNX(hashKey, field, value).Result()if err !=nil{
fmt.Println("Error setting hash field:", err)return}if result {
fmt.Printf("HSetNX: Field %s set to %s successfully.\n", field, value)}else{
fmt.Printf("HSetNX: Field %s already exists in hash %s.\n", field, hashKey)}}
HDel:删除hash中的键值对,支持批量删除
例:
HExists:检测哈希中指定键是否存在
该方法返回布尔值,存在就返回true,不存在返回false
3. List
1. LPush
从列表左边插入数据
// 插入一个数据
rdb.LPush(ctx,"key","data1")// LPush支持一次插入任意个数据
err := rdb.LPush(ctx,"key",1,2,3,4,5).Err()if err !=nil{panic(err)}
2. LPushX
跟LPush的区别是,仅当列表存在的时候才插入数据,用法完全一样。
err := rdb.LPushX(ctx,"key","sss").Err()if err !=nil{panic(err)}
3. RPop
从列表的右边删除第一个数据,并返回删除的数据
val, err := rdb.RPop(ctx,"key").Result()if err !=nil{panic(err)}
fmt.Println(val)
4. RPush
从列表右边插入数据
// 插入一个数据
rdb.RPush(ctx,"key","data1")// 支持一次插入任意个数据
err := rdb.RPush(ctx,"key",1,2,3,4,5).Err()if err !=nil{panic(err)}
5. RPushX
跟RPush的区别是,仅当列表存在的时候才插入数据, 他们用法一样
err := rdb.RPushX(ctx,"key","right_x").Err()if err !=nil{panic(err)}
6. LPop
从列表左边删除第一个数据,并返回删除的数据
val, err := rdb.LPop(ctx,"key").Result()if err !=nil{panic(err)}
fmt.Println(val)
7. LLen
返回列表的大小
val, err := rdb.LLen(ctx,"key").Result()if err !=nil{panic(err)}
fmt.Println(val)
8. LRange
返回列表的一个范围内的数据,也可以返回全部数据
// 返回从0开始到-1位置之间的数据,意思就是返回全部数据
vals, err := rdb.LRange(ctx,"key",0,-1).Result()if err !=nil{panic(err)}
fmt.Println(vals)
9. LRem
删除列表中的数据
// 从列表左边开始,删除100, 如果出现重复元素,仅删除1次,也就是删除第一个
dels, err := rdb.LRem(ctx,"key",1,100).Result()if err !=nil{panic(err)}// 如果存在多个100,则从列表左边开始删除2个100
rdb.LRem(ctx,"key",2,100)// 如果存在多个100,则从列表右边开始删除2个100// 第二个参数负数表示从右边开始删除几个等于100的元素
rdb.LRem(ctx,"key",-2,100)// 如果存在多个100,第二个参数为0,表示删除所有元素等于100的数据
rdb.LRem(ctx,"key",0,100)
10. LIndex
根据索引坐标,查询列表中的数据
// 列表索引从0开始计算,这里返回第6个元素
val, err := rdb.LIndex(ctx,"key",5).Result()if err !=nil{panic(err)}
fmt.Println(val)
11. LInsert
在指定位置插入数据
// 在列表中5的前面插入4// before是之前的意思
err := rdb.LInsert(ctx,"key","before",5,4).Err()if err !=nil{panic(err)}// 在列表中 zhangsan 元素的前面插入 欢迎你
rdb.LInsert(ctx,"key","before","zhangsan","欢迎你")// 在列表中 zhangsan 元素的后面插入 2022
rdb.LInsert(ctx,"key","after","zhangsan","2022")
4. Set
1. SAdd
添加集合元素
// 添加100到集合中
err := rdb.SAdd(ctx,"key",100).Err()if err !=nil{panic(err)}// 将100,200,300添加到集合中
rdb.SAdd(ctx,"key",100,200,300)
2. SCard
获取集合元素个数
size, err := rdb.SCard(ctx,"key").Result()if err !=nil{panic(err)}
fmt.Println(size)
3. SIsMember
判断元素是否在集合中
// 检测100是否包含在集合中
ok,_:= rdb.SIsMember(ctx,"key",100).Result()if ok {
fmt.Println("集合包含指定元素")}
4. SMembers
获取集合中所有的元素
es,_:= rdb.SMembers(ctx,"key").Result()// 返回的es是string数组
fmt.Println(es)
5. SRem
删除集合元素
// 删除集合中的元素100
rdb.SRem(ctx,"key",100)// 删除集合中的元素200和300
rdb.SRem(ctx,"key",200,300)
6. SPop,SPopN
随机返回集合中的元素,并且删除返回的元素
// 随机返回集合中的一个元素,并且删除这个元素
val,_:= rdb.SPop(ctx,"key").Result()
fmt.Println(val)// 随机返回集合中的5个元素,并且删除这些元素
vals,_:= rdb.SPopN(ctx,"key",5).Result()
fmt.Println(vals)
5. sorted set
1. ZAdd
添加一个或者多个元素到集合,如果元素已经存在则更新分数
// 添加一个集合元素到集合中, 这个元素的分数是2.5,元素名是zhangsan
err := rdb.ZAdd(ctx,"key",&redis.Z{Score:2.5, Member:"zhangsan"}).Err()if err !=nil{panic(err)}
2. ZCard
返回集合元素个数
size, err := rdb.ZCard(ctx,"key").Result()if err !=nil{panic(err)}
fmt.Println(size)
3. ZCount
统计某个分数范围内的元素个数
// 返回: 1<=分数<=5 的元素个数, 注意:"1", "5"两个参数是字符串
size, err := rdb.ZCount(ctx,"key","1","5").Result()if err !=nil{panic(err)}
fmt.Println(size)// 返回: 1<分数<=5 的元素个数// 说明:默认第二,第三个参数是大于等于和小于等于的关系。// 如果加上( 则表示大于或者小于,相当于去掉了等于关系。
size, err := rdb.ZCount(ctx,"key","(1","5").Result()
4. ZIncrBy
增加元素的分数
// 给元素zhangsan,加上2分
rdb.ZIncrBy(ctx,"key",2,"zhangsan")
5.ZRange,ZRevRange
返回集合中某个索引范围的元素,根据分数从小到大排序
// 返回从0到-1位置的集合元素, 元素按分数从小到大排序// 0到-1代表则返回全部数据
vals, err := rdb.ZRange(ctx,"key",0,-1).Result()if err !=nil{panic(err)}for_, val :=range vals {
fmt.Println(val)}
ZRevRange用法跟ZRange一样,区别是ZRevRange的结果是按分数从大到小排序。
6. ZRangeByScore
根据分数范围返回集合元素,元素根据分数从小到大排序,支持分页。
// 初始化查询条件, Offset和Count用于分页
op := redis.ZRangeBy{
Min:"2",// 最小分数
Max:"10",// 最大分数
Offset:0,// 类似sql的limit, 表示开始偏移量
Count:5,// 一次返回多少数据}
vals, err := rdb.ZRangeByScore(ctx,"key",&op).Result()if err !=nil{panic(err)}for_, val :=range vals {
fmt.Println(val)}
7. ZRevRangeByScore
用法类似ZRangeByScore,区别是元素根据分数从大到小排序。
8. ZRangeByScoreWithScores
用法跟ZRangeByScore一样,区别是除了返回集合元素,同时也返回元素对应的分数
// 初始化查询条件, Offset和Count用于分页
op := redis.ZRangeBy{
Min:"2",// 最小分数
Max:"10",// 最大分数
Offset:0,// 类似sql的limit, 表示开始偏移量
Count:5,// 一次返回多少数据}
vals, err := rdb.ZRangeByScoreWithScores(ctx,"key",&op).Result()if err !=nil{panic(err)}for_, val :=range vals {
fmt.Println(val.Member)// 集合元素
fmt.Println(val.Score)// 分数}
9. ZRem
删除集合元素
// 删除集合中的元素zhangsan
rdb.ZRem(ctx,"key","zhangsan")// 删除集合中的元素zhangsan和zhangsan1// 支持一次删除多个元素
rdb.ZRem(ctx,"key","zhangsan","zhangsan1")
10. ZRemRangeByRank
根据索引范围删除元素
// 集合元素按分数排序,从最低分到高分,删除第0个元素到第5个元素。// 这里相当于删除最低分的几个元素
rdb.ZRemRangeByRank(ctx,"key",0,5)// 位置参数写成负数,代表从高分开始删除。// 这个例子,删除最高分数的两个元素,-1代表最高分数的位置,-2第二高分,以此类推。
rdb.ZRemRangeByRank(ctx,"key",-1,-2)
11.ZRemRangeByScore
根据分数范围删除元素
// 删除范围: 2<=分数<=5 的元素
rdb.ZRemRangeByScore(ctx,"key","2","5")// 删除范围: 2<=分数<5 的元素
rdb.ZRemRangeByScore(ctx,"key","2","(5")
12. ZScore
查询元素对应的分数
// 查询集合元素zhangsan的分数
score,_:= rdb.ZScore(ctx,"key","zhangsan").Result()
fmt.Println(score)
13. ZRank
根据元素名,查询集合元素在集合中的排名,从0开始算,集合元素按分数从小到大排序
rk,_:= rdb.ZRank(ctx,"key","zhangsan").Result()
fmt.Println(rk)
ZRevRank的作用跟ZRank一样,区别是ZRevRank是按分数从大到小排序。
版权归原作者 佚名涙 所有, 如有侵权,请联系我们删除。