一、介绍与连接
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
来源:https://www.cnblogs.com/forever521Lee/p/9494951.html