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


    一、介绍与连接

    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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ", 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
    ", err)
            return
        }
    
        fmt.Printf("key:%s value:%s
    ", 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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ", 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
    ", err)
            return
        }
    
        fmt.Printf("key:%s value:%s
    ", 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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ", 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
    ", err)
            return
        }
        for _, val := range data { //遍历出来
            fmt.Printf(" value:%s
    ", 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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ", 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
    ", err)
            return
        }
    
        fmt.Printf(" value:%s
    ", 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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ", 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
    ", err)
            return
        }
    
        fmt.Printf(" value:%s
    ", 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
    ", err)
            return
        }
        fmt.Printf("connect redis successful!!!
    ")
        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
    ")
                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
    ") //验证连接
    
                if time.Since(t) < time.Minute { //如果1分钟之内就不验证了,频繁的ping会影响性能
                    return nil
                }
                fmt.Printf("ping conn
    ")
                _, 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
    ", val, err)
    
        //把连接归还到连接池,并不是关闭连接
        conn.Close()
    
        fmt.Printf("==========================
    ")
        conn = pool.Get()
        conn.Do("set", "abc", "3838383833834378473874837483748374")
    
        val, err = redis.String(conn.Do("get", "abc"))
        fmt.Printf("val:%s err:%v
    ", val, err)
    
        //把连接归还到连接池
        conn.Close()
    }
    
    func main() {
        testRedisPool()
    }

     执行结果:

    解释:

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

    三、参考网址

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

    https://studygolang.com/articles/6107

  • 相关阅读:
    CSV文件读取类
    一个参数处理类
    记一个mysql的问题
    php问题小记
    wsl开nginx和php-fpm遇到的几个小问题
    debian apache2.4 virtual host 使用
    debian 安装 apache2和php7
    杂记整理三:php、thinkphp和sql
    杂记整理二:linux与程序安装
    杂记整理一:javascript, jQuery 以及 ECMAscript
  • 原文地址:https://www.cnblogs.com/forever521Lee/p/9494951.html
Copyright © 2020-2023  润新知