Redis在Go中的应用

作者: witchiman | 来源:发表于2017-05-17 16:04 被阅读192次

    转自 http://witchiman.github.io/2017/04/14/go-redis

    Go 作为一种新兴的语言,由于其本身在网络编程方面表现出来的优势,现在受到越来越多开发者们的青睐。不过,也正是因为它太新,相比于一些很成熟的语言,它的第三方库在质量和数量上并不占优势。相信随着时间的变化,Go程序员的群体日益庞大,这个问题最终会得以解决。

    这里主要是介绍第三方库go-redis/redis在Go中的应用。redis是一个高性能的key-value数据库,这个不用多说,现在很多公司都在使用redis。Go语言官方已经提供了对redis的支持,但是没有redis client的官方实现,而go-redis/redis 是一个很好用的第三方库,目前托管在Github上,相比其它关于Go的redis client,上手更简单,虽然它提供的文档不够丰富,但是方法命名上保持了与redis原生命令的一致,见名知义, 稍微研究下就可以马上着手使用。

    准备工作

    首先去Github上把go-redis/redis 通过git clone下载下来,并放到指定的目录。

    git clone git@github.com:go-redis/redis.git $GOPATH/src/github.com/go-redis/redis
    

    导入要用到的包

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

    如果是在本地测试,记得先打开redis-server。
    现在连接到redis-server

    client := redis.NewClient(&redis.Options{
            Addr: "localhost:6379",
            Password: "",      //默认空密码
            DB: 0,             //使用默认数据库
        })
    
    defer client.Close()       //最后关闭
    

    测试连接。如果pint通会收到返回的信息PONG

    pong, err := client.Ping().Result()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Connected result: ", pong)
    

    常见数据类型的操作

    strings的操作

    String 是redis最基本的数据类型,一个key 对应 一个 value。value的最大数据长度是512M,只要不超过这个大小,可以直接存放任意格式的数据。

    存储一个string

     client.Set("str1", "hello redis",0) //忽略错误
    

    读取设定的值

    str := client.Get("str1")
    fmt.Println(str)
    

    删除string

    client.Del("strtest")
    

    lists的操作

    在redis里,list是简单的字符串列表,可以添加一个元素到列表的头部和尾部。

    插入一个值,如果key不存在,新建一个list。

    client.LPush("list","one","two","three") //rpush则在尾部插入
    

    删除list中的值

    client.LRem("list",2,"three") //删除list中前2个value为 ‘three’的元素
    client.LPop("list") //删除头部的值,同理RPop删除尾部的值。
    

    读取list的值。LRange方法第二个参数start是list读取开始的位置,第三个参数end是结束的位置,通过这两个参数设定操作的范围。如果第三个参数的值超过list的的长度,则redis会从list的头部开始遍历,直到读取 end - start +1 个值。

    list, _ := client.LRange("list", 0, 2).Result()
    fmt.Println("List: ", list)
    //output:
    //List:  [three two one]
    
    client.LRem("list",1,"three")   //删除一个“three”
    list, _ := client.LRange("list", 0, 2).Result()      
    fmt.Println("List: ", list)  //从输出发现list中只剩下two 和one,遍历完list后又从头开始遍历再输出一个two
    //output:
    //List: [two one two]
    
    

    hashes的操作

    Hash 非常适合存储对象,比如用户的注册信息等等。一个hash 有多个字段,存储的时候根据需要设定相应字段的值。

    存储hash

    user := make(map[string]interface{})
    user["name"] = "jim"
    user["gender"] = "man"
    user["age"] = 23
    client.HMSet("user",user)
    

    存取单个字段

    client.HSet("user", "name","tom")
    name := client.HGet("user","name")
    fmt.Print(name)
    

    获取整个hash

    hash, _ := client.HGetAll("user").Result()
    for k, v:= range hash{
        fmt.Printf("key: %v, value: %v ",k, v)
    }
    //output:
    //key: name, value: jim key: age, value: 23 key: gender, value: man 
    

    sets的操作

    Set是没有排序的字符串集合,它的特点是里面不允许有重复的元素。还有一种有有序的集合,操作与set类似,只不过多了一个score的属性,通过这个属性可以获取指定顺序的集合。

    新建一个set

    client.SAdd("set", 7, 6, 5, 3)
    

    获得set的元素数量

    count := client.SCard("set")
    

    获取整个set

    nums:= client.SMembers("set")
    fmt.Println("Set:", nums)
    //output:
    //Set: [3 5 6 7]
    

    查看数据库中所有的key

    result, _ := client.Keys("*").Result()
    fmt.Println("Redis value: ", result)
    //output:
    //Redis value:  [pipe list str1 str2 set user]
    

    管道和事务

    管道

    在redis中,管道(Pipleline)可以简单的理解为一系列命令的打包。通常,我们通过redis-cli与redis-server交互时,都是一个命令执行完后,明确收到redis-server的反馈信息时才进行下一个命令。这种交互是堵塞式的,效率比较低下。如:

        client: INCR X
        server: 1
        client: INCR X
        server: 2
        client: INCR X
        server: 3
        ...
    

    使用管道后,多个命令可以放到一起一起执行,其实在管道中redis也是依次执行每个命令的,只是下一个命令不必等到上一个命令执行完反馈到client后再执行。

        client: INCR X
        client: INCR X
        client: INCR X 
        ...
        server: 1
        server: 2
        server: 3
        ...
    

    使用管道。下面代码首先新建一个键 pipe,然后通过三个命令使它的值每次递增1,把这几个命令打包成进一个管道,然后一起执行。

    pl := client.Pipeline()  
    pl.Set("pipe", 0,0)
    pl.Incr("pipe")
    pl.Incr("pipe")
    pl.Incr("pipe")
    pl.Exec()
    p,_ := client.Get("pipe").Result()
    fmt.Println("Pipe: ",p)
    //output:
    //Piple: 3
    

    事务

    Redis也像其它数据库一样提供了事务机制,通过MULTI可以开启一个事务,通过EXEC提交一个事务,DISCARD则可以回滚一个操作,WATCH和UNWATCH可以监控和取消监控指定的key。事务与管理类似,也是多个命令的打包,然后放到一起执行。只不过只要有一个命令执行失败,所有操作都会回滚。在go-redis/redis中使用事务很简单。代码基本上与使用管道一样。

    pl := client.TxPipeline()  //此处只需把Pipleline()换成TxPipleline()
    pl.Set("pipe", 0,0)
    pl.Incr("pipe")
    pl.Incr("pipe")
    pl.Incr("pipe")
    pl.Exec()
    p,_ := client.Get("pipe").Result()
    fmt.Println("Pipe: ",p)
    //output:
    //Transaction: 3
    

    订阅

    Redis中的订阅是一种消息通信机制。订阅者订阅了频道后,只要发送者通过这个频道发送消息,所有的订阅者就会收到消息。

    下列代码通过Publish()创建了名为mychannel 的频道并发布。接着,开启一个goroutine用来订阅这个频道,Subscribe()方法返回一个Pubsub,通过Receive()来接受发布者发布的消息。为了保证在主线程在结束前goroutine收到信息,创建了一个空的chan。

    done := make(chan struct{})
    client.Publish("mychannel", "hello budy!\n")
    go func() {
        pubsub := client.Subscribe("mychannel")
        msg,_ := pubsub.Receive()
        fmt.Println("Receive from channel:", msg)
        done <- struct {}{}
    }()
    
    <-done 
    

    相关文章

      网友评论

        本文标题:Redis在Go中的应用

        本文链接:https://www.haomeiwen.com/subject/vzvdxxtx.html