麻芝酱 發表於 2020-7-12 17:40:00

go操作redis

<div><span style="font-size: 18px">golang操作redis主要有两个库,go-redis和redigo。两者操作都比较简单,区别上redigo更像一个client执行各种操作都是通过Do函数去做的,redis-go对函数的封装更好,相比之下redigo操作redis显得有些繁琐。但是官方更推荐redigo,所以项目中我使用了redigo。</span></div>
<div><span style="font-size: 18px">redigo的使用入门可以去查godoc:http://godoc.org/github.com/garyburd/redigo/redis</span></div>
<div><span style="font-size: 18px">&nbsp;</span></div>
<div><span style="font-size: 18px">引入包:github.com/gomodule/redigo/redis</span></div>
<div><span style="font-size: 18px">&nbsp;</span></div>
<h2><span style="font-size: 18px">连接redis:</span></h2>
<p><span style="font-size: 16px">有好几种连接的方法:</span></p>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">//第一种连接方法
c1,err := redis.Dial("tcp","127.0.0.1:6379")
if err != nil {
   panic(err)
}
defer c1.Close()
//第二种连接方法 其实这个最后还是会调用Dial
c2,err := redis.DialURL("redis://127.0.0.1:6379")
if err != nil {
   panic(err)
}
defer c2.Close()
</pre>
</div>
<p>  </p>
<h2>常用api:</h2>
<p></p>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">//Send + Flush + Receive = Do
rec1,err := c1.Do("Get","gwyy")
fmt.Println(string(rec1.([]byte)))

c2.Send("Get","gwyy")
c2.Flush()
rec2,err := c2.Receive()
fmt.Println(string(rec2.([]byte)))

//set 永不过期
_,err = c1.Do("Set","xhc","xhc hahaha")
if err != nil {
   panic(err)
}
//5秒过期
_,err = c1.Do("Set","xhc1","xhc hahaha","EX",5)
if err != nil {
   panic(err)
}
//检查key是否存在
is_key_exit,err := redis.Bool(c1.Do("EXISTS","gwyy"))
if err != nil {
   panic(err)
}
fmt.Println(is_key_exit)
//删除一个key
_, err = c1.Do("DEL", "mykey")
if err != nil {
   fmt.Println("redis delelte failed:", err)
}
//设置过期时间
n, _ := c1.Do("EXPIRE", "xhc", 24*3600)
fmt.Println(n)

//list 操作
_,_ = c1.Do("lpush","mylist","redis")
_,_ = c1.Do("lpush","mylist","mongodb")
_,_ = c1.Do("lpush","mylist","mysql")
//​ value 将一组命令结果转换为 []interface{}。如果err不等于nil,那么Values返回nil,err
values,_ := redis.Values(c1.Do("lrange","mylist","0","-1"))
for _,v := range values {
   fmt.Println(string(v.([]byte)))
}
</pre>
</div>
<p>  </p>
<h2 id="9366-1594545647996">Do传参Args:</h2>
<div><span style="font-size: 16px">定义:type Args []interface{}</span></div>
<div><span style="font-size: 16px">Args是帮助构造结构化值的命令参数,一般用在Hmset</span></div>
<div>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">type Book struct {
   BookNamestring
   Author    string
   PageCount string
   Press   string
}
top1 := Book{
   BookName:"Crazy golang",
   Author:    "Moon",
   PageCount: "600",
   Press:   "GoodBook",
}

if _, err := c1.Do("HMSET", redis.Args{}.Add("Top1").AddFlat(&amp;top1)...); err != nil {
   fmt.Println(err)
}
topx := Book{}
for _, item := range []string{"Top1"} {
   value, _ := redis.Values(c1.Do("HGETALL", item))
    redis.ScanStruct(value, &amp;topx)
   fmt.Printf("%s[%+v]\n", item, topx)
}
stringsValue, _ := redis.Strings(c1.Do("HMGET", "Top1", "BookName", "Author"))
fmt.Printf("hmget:%+v\n", stringsValue)

//普通命令也可以用args展开
dd := redis.Args{}.Add("aa11").AddFlat("bb")
c1.Do("Set",dd...)<br><br>
//redis mget 两种用法
args := redis.Args{}
args = args.Add("gwyy").Add("pipe1").Add("aa11")
//[ ]
//mget 默认会返回[]interface{} 如果直接拿来用 需要自己强转一遍
rec1,err1 := c1.Do("MGET",args...)
if err1 != nil {fmt.Println(err1)}
for _,v:= range rec1.([]interface{}) {
   fmt.Println(string(v.([]byte)))
}

//可以用redis 封装的 ByteSlices 直接帮你转换
//[ ]   slice
rec1,err1 := redis.ByteSlices(c1.Do("MGET",args...))
</pre>
</div>
<p>  </p>
</div>
<div>
<p>  </p>
</div>
<p>  </p>
<h2 id="5852-1594545645255">管道操作:</h2>
<div><span style="font-size: 16px">Send 向谅解的输出缓冲中写入命令, Flush将链接输出缓冲清空并写入服务端,Recevie按照FIFO 顺序依次读取服务器的响应。</span></div>
<p><span style="font-size: 16px"></span></p>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">//管道SendFlush Receive
//Send 向谅解的输出缓冲中写入命令, Flush将链接输出缓冲清空并写入服务端,Recevie按照FIFO 顺序依次读取服务器的响应
c1.Send("SET","pipe1","111")
c1.Send("GET","pipe1")
c1.Send("GET","xhc")
c1.Flush()
c1.Receive() //返回了 set
v,err :=c1.Receive() //返回了getpipe1
v1,err :=c1.Receive() //返回了get xhc
fmt.Println(string(v.([]byte)))
fmt.Println(string(v1.([]byte)))
//Do方法组合了Send,Flush和 Receive方法。Do方法先写入命令,然后清空输出buffer,最后接收全部挂起响应包括Do方发出的命令的结果。
//如果任何响应中包含一个错误,Do返回错误。如果没有错误,Do方法返回最后一个响应。
</pre>
</div>
<p>  </p>
<h2>连接池:</h2>
<div><span style="font-size: 16px">在golang的项目中,若要频繁的用redis(或者其他类似的NoSQL)来存取数据,最好用redigo自带的池来管理连接。</span></div>
<div><span style="font-size: 16px">不然的话,每当要操作redis时,建立连接,用完后再关闭,会导致大量的连接处于TIME_WAIT状态(redis连接本质上就是tcp)。</span></div>
<div><span style="font-size: 16px">注:TIME_WAIT,也叫TCP半连接状态,会继续占用本地端口。</span></div>
<p></p>
<div class="cnblogs_Highlighter">
<pre class="brush:go;gutter:true;">var RedisClient *redis.Pool
RedisClient = &amp;redis.Pool{
   //连接方法
   Dial:            func() (redis.Conn,error) {
      c,err := redis.Dial("tcp","127.0.0.1:6379")
      if err != nil {
         return nil,err
      }
      c.Do("SELECT",0)
      return c,nil
   },
   //DialContext:   nil,
   //TestOnBorrow:    nil,
   //最大的空闲连接数,表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态。
   MaxIdle:         1,
   //最大的激活连接数,表示同时最多有N个连接
   MaxActive:       10,
   //最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭
   IdleTimeout:   180 * time.Second,
   //Wait:            false,
   //MaxConnLifetime: 0,
}
//拿到一个连接
c1 := RedisClient.Get()
defer c1.Close()
r,_ := c1.Do("GET","xhc")
fmt.Println(string(r.([]byte)))
</pre>
</div>
<p>  </p>
<p>&nbsp;</p>
</div>
<p></p><br><br>
来源:https://www.cnblogs.com/gwyy/p/13289126.html
頁: [1]
查看完整版本: go操作redis