10

golang 操作redis5大数据类型(string、hash、list、set、zset)(go-redis)

 4 years ago
source link: https://studygolang.com/articles/26489
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

使用redis首先要部署redis,载个安装包,部署下即可,本文不赘述了。redis官网: https://redis.io/

接着要下载golang的redis资源包,golang官方推荐的有redisgo和go-reids,个人认为go-redis的封装更加人性化,redisgo的调用是基于命令的,go-redis是基于方法的,所以本文先来介绍go-redis的使用。

2行代码来比较下2种资源包的调用方式:

redisgo: client.Do("SET", "mykey", "我是数据", "EX", "3600")
go-redis: client.Set("mykey", "我是数据", time.Hour)

同样是存储一个1小时后过期的数据,go-redis的调用方式明显更友好。

导入go-redis包

github地址: https://github.com/go-redis/redis

文档地址: https://godoc.org/github.com/go-redis/redis

golang下载资源包相当方便,打开命令行,输入命令: go get -u github.com/go-redis/redis (使用git命令下载资源包,需要先安装git,没安装git的同学可以手动下载后放入src目录下)。

3E3ueqM.png!web

下载完成会在GOPATH下的src里多了资源包

3qMbAvi.png!web

导入包:

import (  
    "github.com/go-redis/redis" 
)

1、链接redis

client := redis.NewClient(&redis.Options{  
    Addr:     "127.0.0.1:6379",  
    Password: "123456",  
    DB:       0,  
})  
//延迟到程序结束关闭链接
defer client.Close()  
//ping
pong, err := client.Ping().Result()  
if err != nil {  
   fmt.Println("ping error", err.Error())  
   return  
}  
fmt.Println("ping result:", pong)

解析:

Addr 是redis服务的地址,如果部署的reids没有密码,那 Password 就写 ""DB 是对应reids 0-15的db

测试redis链接:

pong, err := client.Ping().Result()

2、string 字符串

//string------------------------------------------------------------------------  
key := "go2key"  
//过期时间1小时  
err = client.Set(key, "我是值", time.Hour).Err()  
if err != nil {  
   fmt.Println("set err", err)  
   return  
}  
  
//获取  
value, err := client.Get(key).Result()  
if err != nil {  
   fmt.Println("Get err", err)  
   return  
}  
fmt.Printf("key:%v 值:%~~~~v \n", key, value)
存储命令:Set,过期时间如果是3分钟则写成 3*timt.Minute
client.Set(key, "我是值", time.Hour)

读取命令:Get

value, err := client.Get(key).Result()

3、struc 结构

//json---------------------------------
//存储结构  
doctor := Doctor{1, "钟南山", 83, 1, time.Now()}  
doctorJson, _ := json.Marshal(doctor)  
client.Set("doctor2", doctorJson, time.Hour)  
  
//读取结构  
doctorResult, _ := client.Get("doctor2").Result()  
var doctor2 Doctor  
//反序列化  
json.Unmarshal([]byte(doctorResult), &doctor2)  
fmt.Println("doctor2", doctor2)

解析:

存储结构其实也是存储string,只是把struc序列化成json,等读取的时候再反序列化成struc

序列化:

doctorJson, _ := json.Marshal(doctor)

反序列化:

json.Unmarshal([]byte(doctorResult), &doctor2)

4、list 列表

list是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

//list----------------------------------------------------  
//通道列表 list
listKey := "go2list"  
client.RPush(listKey, "str1", 10, "str2", 15, "str3", 20).Err()  
  
//lpop 取出并移除左边第一个元素  
first, _ := client.LPop(listKey).Result()  
fmt.Printf("列表第一个元素 key:%v value:%v \n", first[0], first[1])  
  
//Blpop 取出并移除左边第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。  
first2, _ := client.BLPop(time.Second*60, listKey).Result()  
fmt.Printf("列表第一个元素 key:%v value:%v \n", first2[0], first2[1])  
  
//数据长度  
listLen, _ := client.LLen(listKey).Result()  
fmt.Println("list length", listLen)  
  
//获取列表  
listGet, _ := client.LRange(listKey, 1, 2).Result()  
fmt.Println("索引1-2的2个元素元素", listGet)

解析:

存储 "str1", 10, "str2", 15, "str3", 20 这6个元素到 "go2list" 中,使用RPush命令往队列右边加入。

从左边取出第一个元素,取出后,这个元素将会从list里移除,这就很像我们的消息队列了。

first, _ := client.LPop(listKey).Result()

BLPop获取左边第一个元素,如果不存在元素,则会一直堵塞,直到 time.Second*60 60秒内有数据加入,被取出为止。

first2, _ := client.BLPop(time.Second*60, listKey).Result()

获取整个列表数据,这是不会移除数据的

listGet, _ := client.LRange(listKey, 1, 2).Result()

关于list的命令还有很多,例如LPush、Rpop、BRpop、LLen等等

5、hash

hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。可以不用直接获取和更新对象的某个属性。

//hash-------------------------------------------  
hashKey := "userkey_1"  
//set hash 适合存储结构  
client.HSet(hashKey, "name", "叶子")  
client.HSet(hashKey, "age", 18)  
  
//get hash  
hashGet, _ := client.HGet(hashKey, "name").Result()  
fmt.Println("HGet name", hashGet)  
  
//获取所有hash 返回map  
hashGetAll, _ := client.HGetAll(hashKey).Result()  
fmt.Println("HGetAll", hashGetAll)

解析:

存储name属性为叶子,age属性为18的对象到userkey_1中

client.HSet(hashKey, "name", "叶子")

获取某个属性

hashGet, _ := client.HGet(hashKey, "name").Result()

获取userkey_1所有的属性,返回的是一个map对象

hashGetAll, _ := client.HGetAll(hashKey).Result()

6、set 集合

set 是 string 类型的无序集合。

//set-------------------------------------------- 
setKey := "go2set"  
client.SAdd(setKey, "set1")  
client.SAdd(setKey, "set2")  
client.SAdd(setKey, "set3")  
client.SAdd(setKey, "set4")  
  
//获取集合的所有成员  
setList, _ := client.SMembers(setKey).Result()  
fmt.Println("GetSet", setList)  
//移除集合里的set1  
client.SRem(setKey, "set1")  
  
//移除并返回set的一个随机元素  
setFirst, _ := client.SPop(setKey).Result()  
fmt.Println("setFirst", setFirst)

解析:

往集合里添加数据

client.SAdd(setKey, "set1")

获取集合的所有的元素

setList, _ := client.SMembers(setKey).Result()

移除并返回set的一个随机元素,因为set是无序的

setFirst, _ := client.SPop(setKey).Result()

6、zset 有序集合

set是有序的,适合做排行榜业务,我们来模拟一个医生热度排行

//zset------------------------------------------------  
zsetKey := "go2zset"  
ranking := []*redis.Z{  
  &redis.Z{Score: 100.0, Member: "钟南山"},  
  &redis.Z{Score: 80.0, Member: "林医生"},  
  &redis.Z{Score: 70.0, Member: "王医生"},  
  &redis.Z{Score: 75.0, Member: "张医生"},  
  &redis.Z{Score: 59.0, Member: "叶医生"},  
}  
client.ZAdd(zsetKey, ranking...)  
//golang+5分  
newScore, err := client.ZIncrBy(zsetKey, 5.0, "钟南山").Result()  
fmt.Println("钟南山加5分后的最新分数", newScore)  
//取zset里的前2名热度的医生  
zsetList2, _ := client.ZRevRangeWithScores(zsetKey, 0, 1).Result()  
fmt.Println("zset前2名热度的医生", zsetList2)

解析:

往zset里加入集合数据,数据是 []*redis.Z 类型,里面包含 ScoreMember 2个属性

client.ZAdd(zsetKey, ranking...)

给钟南山加上5分,返回钟南山的最新热度分值

newScore, err := client.ZIncrBy(zsetKey, 5.0, "钟南山").Result()

获取前2名热度的医生,前2名,所以索引是从0到1。

zsetList2, _ := client.ZRevRangeWithScores(zsetKey, 0, 1).Result()

7、设置过期时间

操作string数据的时候,可以在方法里直接传入过期时间。但list、hash、set、zset都没有直接提供相应参数,但redis可以额外设置key的过期时间

//Expire------------------------------------------ 
//设置过期时间 30秒后过期  
client.Expire(hashKey, time.Second*30)  
client.ExpireAt(hashKey, time.Now().Add(time.Second*30))  
//删除key  
//client.Del("go2key", "go2list")  
  
//ttl 获取key的生存时间  
duration, err := client.TTL(key).Result()  
if err != nil {  
   fmt.Println("TTL err", err)  
   return  
}  
fmt.Printf("key%v的有效时间,%v,%v \n", key, duration.String(), duration.Seconds())

完整demo

package main

import (
    "encoding/json"
    "fmt"
    "github.com/go-redis/redis"
    "time"
)

type Doctor struct {  
    ID      int64  
    Name    string  
    Age     int  
    Sex     int  
    AddTime time.Time  
}

func main() {
    client := redis.NewClient(&redis.Options{
        Addr:     "127.0.0.1:6379",
        Password: "123456",
        DB:       0,
    })
    //延迟到程序结束关闭链接
    defer client.Close()
    //ping
    pong, err := client.Ping().Result()
    if err != nil {
        fmt.Println("ping error", err.Error())
        return
    }
    fmt.Println("ping result:", pong)

    //string------------------------------------------------------------------------
    key := "go2key"
    //过期时间1小时
    err = client.Set(key, "我是值", time.Hour).Err()
    if err != nil {
        fmt.Println("set err", err)
        return
    }

    //获取
    value, err := client.Get(key).Result()
    if err != nil {
        fmt.Println("Get err", err)
        return
    }
    fmt.Printf("key:%v 值:%v \n", key, value)

    //list------------------------------------------------------------------------
    //通道列表 list
    listKey := "go2list"
    client.RPush(listKey, "str1", 10, "str2", 15, "str3", 20).Err()

    //lpop 取出并移除左边第一个元素
    first, _ := client.LPop(listKey).Result()
    fmt.Printf("列表第一个元素 key:%v value:%v \n", first[0], first[1])

    //Blpop 取出并移除左边第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
    first2, _ := client.BLPop(time.Second*60, listKey).Result()
    fmt.Printf("列表第一个元素 key:%v value:%v \n", first2[0], first2[1])

    //数据长度
    listLen, _ := client.LLen(listKey).Result()
    fmt.Println("list length", listLen)

    //获取列表
    listGet, _ := client.LRange(listKey, 1, 2).Result()
    fmt.Println("索引1-2的2个元素元素", listGet)

    //json------------------------------------------------------------------------
    //存储结构
    doctor := Doctor{1, "钟南山", 83, 1, time.Now()}
    doctorJson, _ := json.Marshal(doctor)
    client.Set("doctor2", doctorJson, time.Hour)

    //读取结构
    doctorResult, _ := client.Get("doctor2").Result()
    var doctor2 Doctor
    //反序列化
    json.Unmarshal([]byte(doctorResult), &doctor2)
    fmt.Println("doctor2", doctor2)

    //hash------------------------------------------------------------------------
    hashKey := "gohash"
    //set hash 适合存储结构
    client.HSet(hashKey, "name", "叶子")
    client.HSet(hashKey, "age", 18)

    //get hash
    hashGet, _ := client.HGet(hashKey, "name").Result()
    fmt.Println("HGet name", hashGet)

    //获取所有hash 返回map
    hashGetAll, _ := client.HGetAll(hashKey).Result()
    fmt.Println("HGetAll", hashGetAll)

    //set------------------------------------------------------------------------
    setKey := "go2set"
    client.SAdd(setKey, "set1")
    client.SAdd(setKey, "set2")
    client.SAdd(setKey, "set3")
    client.SAdd(setKey, "set4")

    //获取集合的所有成员
    setList, _ := client.SMembers(setKey).Result()
    fmt.Println("GetSet", setList)
    //移除集合里的set1
    client.SRem(setKey, "set1")

    //移除并返回set的一个随机元素
    setFirst, _ := client.SPop(setKey).Result()
    fmt.Println("set的随机元素", setFirst)

    //zset------------------------------------------------------------------------
    zsetKey := "go2zset"
    ranking := []*redis.Z{
        &redis.Z{Score: 100.0, Member: "钟南山"},
        &redis.Z{Score: 80.0, Member: "林医生"},
        &redis.Z{Score: 70.0, Member: "王医生"},
        &redis.Z{Score: 75.0, Member: "张医生"},
        &redis.Z{Score: 59.0, Member: "叶医生"},
    }
    client.ZAdd(zsetKey, ranking...)
    //golang+5分
    newScore, err := client.ZIncrBy(zsetKey, 5.0, "钟南山").Result()
    fmt.Println("钟南山加5分后的最新分数", newScore)
    //取zset里的前2名热度的医生
    zsetList2, _ := client.ZRevRangeWithScores(zsetKey, 0, 1).Result()
    fmt.Println("zset前2名热度的医生", zsetList2)

    //Expire------------------------------------------------------------------------
    //设置过期时间 30秒后过期
    client.Expire(hashKey, time.Second*30)
    client.ExpireAt(hashKey, time.Now().Add(time.Second*30))
    //删除key
    //client.Del("go2key", "go2list")

    //ttl 获取key的生存时间
    duration, err := client.TTL(key).Result()
    if err != nil {
        fmt.Println("TTL err", err)
        return
    }
    fmt.Printf("key%v的有效时间,%v,%v \n", key, duration.String(), duration.Seconds())
}

总结

以上就是redis常用的方法示例,go-redis的封装非常的友好,所有的方法名与redis自己的命令都是相对应的,非常易于理解,即便不看文档,只要你熟悉redis命令,使用起来也是很顺畅的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK