Go语言基础之17--Redis基本操作

懵懂的女人 提交于 2020-02-01 09:19:16

一、介绍与连接

1.1 介绍

使用第三方的redis库, github.com/garyburd/redigo/redis

github地址:https://github.com/gomodule/redigo

下载:

go get github.com/garyburd/redigo

 

1.2 连接redis

package main

import (
    "fmt"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func main() {
    conn, err := initRedis()
    if err != nil {
        return
    }
    defer conn.Close() //关闭连接
}

 执行结果:

二、redis开发

2.1 set操作

package main

import (
    "fmt"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func testSetGet(conn redis.Conn) {
    key := "abc"
    _, err := conn.Do("set", key, "this is a test") //用do函数来进行redis命令操作
    if err != nil {
        fmt.Printf("set failed:%s\n", err)
        return
    }

    //reply, err := conn.Do("get", "abc") //get返回的是1个空接口,我们不知道里面内容到底什么类型,所以要做一次转换
    data, err := redis.String(conn.Do("get", key)) //因为我们知道存的是string,所以转换时是redis.string,如果存的是int,那就是redis.int
    if err != nil {
        fmt.Printf("get failed, err:%v\n", err)
        return
    }

    fmt.Printf("key:%s value:%s\n", key, data)
}

func main() {
    conn, err := initRedis()
    if err != nil {
        return
    }
    defer conn.Close() //关闭连接

    testSetGet(conn)
}

 执行结果:

2.2 hash表操作

hash表是把一类的数据聚合在一块。比如books表存的都是书籍相关的数据

package main

import (
    "fmt"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func testHSetGet(conn redis.Conn) {
    key := "abc"
    _, err := conn.Do("hset", "books", key, "this is a test") //books是哈希表名 其中存的是一条条key-value
    if err != nil {
        fmt.Printf("set failed:%s\n", err)
        return
    }

    //reply, err := conn.Do("get", "abc")
    data, err := redis.String(conn.Do("hget", "books", key))
    if err != nil {
        fmt.Printf("get failed, err:%v\n", err)
        return
    }

    fmt.Printf("key:%s value:%s\n", key, data)
}

func main() {
    conn, err := initRedis()
    if err != nil {
        return
    }
    defer conn.Close() //关闭连接

    testHSetGet(conn)
}

执行结果:

2.3 mset操作

并发批量操作

package main

import (
    "fmt"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func testMSetGet(conn redis.Conn) {
    key := "abc"
    key1 := "efg"
    _, err := conn.Do("mset", key, "this is a test", key1, "ksksksksks") //一次设置多个key
    if err != nil {
        fmt.Printf("set failed:%s\n", err)
        return
    }

    //reply, err := conn.Do("get", "abc")
    data, err := redis.Strings(conn.Do("mget", key, key1)) //一次读取多个 。返回的data是1个切片,这里用strings函数
    if err != nil {
        fmt.Printf("get failed, err:%v\n", err)
        return
    }
    for _, val := range data { //遍历出来
        fmt.Printf(" value:%s\n", val)
    }
}

func main() {
    conn, err := initRedis()
    if err != nil {
        return
    }
    defer conn.Close() //关闭连接

    testMSetGet(conn)
}

 执行结果:

2.4 设置过期时间

package main

import (
    "fmt"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func testExpire(conn redis.Conn) {
    _, err := conn.Do("expire", "abc", 20)  //设置key为abc的过期时间为20s
    if err != nil {
        fmt.Println(err)
        return
    }
}

func main() {
    conn, err := initRedis()
    if err != nil {
        return
    }
    defer conn.Close() //关闭连接

    testExpire(conn)
}

 执行结果:

2.5 队列和栈操作

有4个方法:

lpush:左入队

rpush:右入队

lpop:左出队

rpop:右出队

队列:先进先出

栈:先进后出

 

队列实例:

package main

import (
    "fmt"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func testList(conn redis.Conn) {

    _, err := conn.Do("lpush", "book_list", "this is a test", "ksksksksks") //左边进 第二个参数book_lsit是队列名
    if err != nil {
        fmt.Printf("set failed:%s\n", err)
        return
    }

    //reply, err := conn.Do("get", "abc")
    data, err := redis.String(conn.Do("rpop", "book_list")) //右边出,一次只能出队一个元素
    if err != nil {
        fmt.Printf("get failed, err:%v\n", err)
        return
    }

    fmt.Printf(" value:%s\n", data)
}

func main() {
    conn, err := initRedis()
    if err != nil {
        return
    }
    defer conn.Close() //关闭连接

    testList(conn)
}

 执行结果:

 

栈操作实例:

package main

import (
    "fmt"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func testList(conn redis.Conn) {

    _, err := conn.Do("lpush", "book_stack", "this is a test", "ksksksksks") //左边进 第二个参数book_lsit是队列名
    if err != nil {
        fmt.Printf("set failed:%s\n", err)
        return
    }

    //reply, err := conn.Do("get", "abc")
    data, err := redis.String(conn.Do("lpop", "book_list")) //左边出,一次只能出队一个元素
    if err != nil {
        fmt.Printf("get failed, err:%v\n", err)
        return
    }

    fmt.Printf(" value:%s\n", data)
}

func main() {
    conn, err := initRedis()
    if err != nil {
        return
    }
    defer conn.Close() //关闭连接

    testList(conn)
}

 执行结果:

2.6 redis连接池

之前实例都是单个连接,拿到1个连接,针对连接进行操作,如果是1个并发的程序,1个连接是不够的,并且会有线程安全的问题,但是我们可以用连接池来解决。

package main

import (
    "fmt"
    "time"

    "github.com/garyburd/redigo/redis"
)

func initRedis() (conn redis.Conn, err error) { //连接redis函数
    conn, err = redis.Dial("tcp", "127.0.0.1:6379") //传递协议、ip、端口
    if err != nil {
        fmt.Printf("conn redis failed, err:%v\n", err)
        return
    }
    fmt.Printf("connect redis successful!!!\n")
    return
}

func newPool(serverAddr string, passwd string) (pool *redis.Pool) { //第一个参数是服务的地址,第二个是连接时的密码(就是redis的密码)
    return &redis.Pool{ //返回1个结构体的连接池对象
        MaxIdle:     16,                //空闲连接数,即使没有连接请求,也会有空闲连接数在连接池中
        MaxActive:   1024,              //活跃连接数,也就是最大连接数
        IdleTimeout: 240 * time.Second, //空闲连接数超时时间,连接数超时了就会被释放掉
        Dial: func() (redis.Conn, error) { //匿名函数类型变量,用来连接redis
            fmt.Printf("create conn\n")
            conn, err := redis.Dial("tcp", serverAddr)
            if err != nil {
                return nil, err
            }

            if len(passwd) > 0 {
                _, err = conn.Do("auth", passwd)
                if err != nil {
                    return nil, err
                }
            }
            return conn, err
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error { //匿名函数类型变量,作用:如果从连接池获取连接时,会验证一下这个连接是不是可用的。
            fmt.Printf("verify conn\n") //验证连接

            if time.Since(t) < time.Minute { //如果1分钟之内就不验证了,频繁的ping会影响性能
                return nil
            }
            fmt.Printf("ping conn\n")
            _, err := c.Do("ping")
            return err
        },
    }
}

func testRedisPool() {
    pool := newPool("127.0.0.1:6379", "")

    conn := pool.Get() //获取1个连接
    conn.Do("set", "abc", "3838383833834378473874837483748374")

    val, err := redis.String(conn.Do("get", "abc"))
    fmt.Printf("val:%s err:%v\n", val, err)

    //把连接归还到连接池,并不是关闭连接
    conn.Close()

    fmt.Printf("==========================\n")
    conn = pool.Get()
    conn.Do("set", "abc", "3838383833834378473874837483748374")

    val, err = redis.String(conn.Do("get", "abc"))
    fmt.Printf("val:%s err:%v\n", val, err)

    //把连接归还到连接池
    conn.Close()
}

func main() {
    testRedisPool()
}

 执行结果:

解释:

我们可以发现第一次我们get是建立了连接,在使用完之后close(将该连接归还到连接池了),紧接着下面一个请求,get并没有建立新的连接,而是使用了连接池中刚刚归还的连接,并且因为小于我们的设定时间,也没有去ping redis

三、参考网址

https://www.jianshu.com/p/89ca34b84101

https://studygolang.com/articles/6107

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!