一、介绍与连接
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