Go进阶(1): Golang + Goland 研究Redis的基本操作与函数接口
1. 开发环境搭建
-
GOROOT变量值是安装的go路径
-
PATH环境变量就是%GOROOT%\bin路径
-
GOPATH环境变量是工作目录,就是写代码的目录,编译源代码等生成的文件都会放到这个目录下
Note:需要在工作目录下新建三个文件夹,分别是bin、pkg、src;src 目录存放的是我们的go源代码,不同工程项目的代码以包名区分;pkg 中存放编译后生成的文件(比如:.a);bin文件夹存放go install命名生成的可执行文件; 建议把GOPATH/bin加到系统的环境变量path里面,这样就可以直接在终端里使用我们go开发生成的程序。
2. 初步配置Redisgo并调试/windows
- 先安装Git,国内比较快的网址链接https://github.com/waylau/git-for-win
- 建议在%GOPATH%src中先创建Go工程,如redisTesting
- 然后在main.go中直接 import redis "github.com/gomodule/redigo/redis";此时,Goland会自动提示安装包的拉取,Redis包就在%GOPATH%pkg目录中。
- 作为备选,可以在Goland终端中执行 go get -v github.com/gomodule/redigo
在%GOPATH%src的redisTesting工程的mian.go函数中输入测试代码:
[code]package main import ( "fmt" "github.com/gomodule/redigo/redis" ) func main() { // 使用redis封装的Dial进行tcp连接 rds,err := redis.Dial("tcp","localhost:32771") errCheck(err) defer rds.Close() //对本次连接进行set操作 _,setErr := rds.Do("set","url","xxbandy.github.io") errCheck(setErr) //使用redis的string类型获取set的k/v信息 r,getErr := redis.String(rds.Do("get","url")) errCheck(getErr) fmt.Println(r) } func errCheck(err error) { if err != nil { fmt.Println("sorry,has some error:",err) return } }
进一步:
- 终端执行 go build main.go 组建
- 终端执行 go run main.go 运行
3. Redis的Golang接口函数
- 链接功能
Conn
接口是redis操作过程中比较重要的接口。应用一般通过调用Dial、DialWithTimeout、NewConn
函数来创建一个链接。Note: 应用必须在操作redis结束之后去调用该连接的Close
方法来关闭连接,以防止资源消耗以及其他问题。
Conn接口的相关方法如下:
[code]type Conn interference{ // 关闭链接 Close() error // 当连接不可用的情况下,返回非空值 Err() error // Do方法是指向redis服务器发送命令 并 返回接收到的命令 Do(commandName string, args ...interface{}) (reply interface{}, err error) // Send将相关的命令写入到客户端的buffer中 Send(commandName string, arg ...interface{}) error // Flush将客户端的输出缓冲内容刷新到redis服务器端 Flush() error // Receive从redis服务端接受单个回复 Receive() (reply interface{}, err error) }
常用的创建Conn的方式:
[code]// 使用Dial函数 // func Dial(network, address string, options ...DialOption) (Conn, error) /*可选的参数 func DialConnectTimeout(d time.Duration) DialOption func DialDatabase(db int) DialOption func DialKeepAlive(d time.Duration) DialOption func DialNetDial(dial func(network, addr string) (net.Conn, error)) DialOption func DialPassword(password string) DialOption func DialReadTimeout(d time.Duration) DialOption func DialWriteTimeout(d time.Duration) DialOption */ rds,err := redis.Dial("tcp","localhost:32771") defer rds.Close() // 使用DialTimeout函数(默认增加了连接、读写超时时间) // func DialTimeout(network, address string, connectTimeout, readTimeout, writeTimeout time.Duration) (Conn, error) // 使用NewConn函数(将一个网络连接转换成redis连接) // func NewConn(netConn net.Conn, readTimeout, writeTimeout time.Duration) Conn
- Redis命令的执行
一般采用Do()方法执行redis命令操作。
[code]package main // Redis链接+执行 import ( "fmt" "time" redis "github.com/gomodule/redigo/redis" ) func main() { // 使用Dial进行tcp连接.设置长连接时间为1s,连接超时时间为5s,读写超时均为1s,并设置密码连接 // 由于redis服务器设置了密码,如果密码错误会报异常: ERR invalid password rds,err := redis.Dial("tcp", "localhost:32771", redis.DialKeepAlive(1*time.Second), redis.DialPassword("ziheng"), redis.DialConnectTimeout(5*time.Second), redis.DialReadTimeout(1*time.Second), redis.DialWriteTimeout(1*time.Second)) fmt.Println(err) defer rds.Close() // 使用Conn的Do方法来操作redis命令 // Do(commandName string, args ...interface{}) (reply interface{}, err error) // 使用redis的string类型获取set的k/v信息 r,getErr := redis.String(rds.Do("get","url")) fmt.Println(getErr) fmt.Println(r) }
- 使用Pipelining操作redis
Note:建议使用redis自身包含的命令进行批量操作而不是使用pipelining,比如
mset、mget、hmset、hmget等等。原子性可能会更好一些。
Conn会使用
Send、Flush、Receive来支持pipeline操作。
Send
会写入命令到连接的输出缓冲区里。
Flush
会将输出缓冲区中的数据刷新到服务端。
Receive
回去服务器端读取单个响应。
[code]rds.Send("SET", "foo", "bar") rds.Flush() v, err = rds.Receive()
其实,在
Do()方法中包含了
Send、Flush、Receive等方法。例如,使用
Send()和
Do()方法来实现pipeline:
- 并发处理
一般并发访问redis,社区中大部分专家建议使用安全线程池去获取连接,从一个goroutine中使用和释放一个链接。正如前面提到的,从线程池中获取的连接会有并发限制。
- 发布/订阅模式(Publish and Subscribe)
使用
Send、Flush、Receive等方法来实现Pub/Sub订阅,例如:
[code]rds.Send("SUBSCRIBE","ANSIBLE-KEY") rds.Flush() for { reply,err := rds.Receive() if err != nil { return err } //process pushed message }
PubSubConn
类型用convenience
方法包装了一个Conn
实现了订阅,
Subscribe PSubscribe Unsubscribe PUnsubscribe方法会send并且flush一个订阅管理命令。接收方法会将push的消息转换成一个可以进行
switch的合适类型。例如:
[code]psc := redis.PubSubConn{Conn: c} psc.Subscribe("example") for { switch v := psc.Receive().(type) { case redis.Message: fmt.Printf("%s: message: %s\n", v.Channel, v.Data) case redis.Subscription: fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count) case error: return v } }
3. Redigo操作redis的应用场景
- 使用
String和Int
获取字符串类型的输出
就是set get mset mget
之类的命令。 Note:当获取数字类型的key时需要使用redis.Int()获取数字类型的输出结果。例如,我想获取string类型的name, Int类型的id:
[code]func main() { c,connErr := redisConn("localhost","32771","ziheng") errCheck("connErr",connErr) getV,_ := redis.String(c.Do("get","name")) getV2,_ := redis.Int(c.Do("get","id")) fmt.Println(getV,getV2) //output1 = "shenziheng"; output2 = "0001" // mget name id 同理 }
- 使用
redis
的安全链连接池
使用连接池可以高效的管理redis的连接,并可以方便地控制redis的并发性能。相关结构体/方法/实例如下:
[code]// 相关的结构体和方法 type Pool struct { //创建一个tcp链接的匿名函数 Dial func() (Conn, error) //可选的函数,用来对之前使用过的空闲链接进行安全检查 TestOnBorrow func(c Conn, t time.Time) error //最大可用链接数 MaxIdle int //在给定的时间,最大可分配的连接数。为0则不限制 MaxActive int //空闲链接的关闭时间,如果为空,空闲链接不会被关闭 IdleTimeout time.Duration //如果Wait为true并且进行MaxActive限制了,Get()将会等待链接被返回 Wait bool //关闭老链接的时间区间。如果为空则不会在生命周期内关闭链接 MaxConnLifetime time.Duration } //创建一个Pool结构体 func NewPool(newFn func() (Conn, error), maxIdle int) *Pool // 获取pool的连接数,包含空闲链接和使用连接 func (p *Pool) ActiveCount() int //关闭并释放pool中的资源 func (p *Pool) Close() error //从pool中获取一个连接 func (p *Pool) Get() Conn // 获取空闲链接数 func (p *Pool) IdleCount() int // 获取连接池的状态信息 func (p *Pool) Stats() PoolStats type PoolStats struct { ActiveCount int IdleCount int }
[code]package main import ( "fmt" "time" "os" "github.com/gomodule/redigo/redis" ) //构造一个链接函数,如果没有密码,passwd为空字符串 func redisConn(ip,port,passwd string) (redis.Conn, error) { rds,err := redis.Dial("tcp", ip+":"+port, redis.DialConnectTimeout(5*time.Second), redis.DialReadTimeout(1*time.Second), redis.DialWriteTimeout(1*time.Second), redis.DialPassword(passwd), redis.DialKeepAlive(1*time.Second), ) return rds,err } //构造一个错误检查函数 func errCheck(tp string,err error) { if err != nil { fmt.Printf("sorry,has some error for %s.\r\n",tp,err) os.Exit(-1) } } //构造一个连接池 //url为包装了redis的连接参数ip,port,passwd func newPool(ip,port,passwd string) *redis.Pool { return &redis.Pool{ MaxIdle: 5, //定义redis连接池中最大的空闲链接为3 MaxActive: 18, //在给定时间已分配的最大连接数(限制并发数) IdleTimeout: 240 * time.Second, MaxConnLifetime: 300 * time.Second, Dial: func() (redis.Conn,error) { return redisConn(ip,port,passwd) }, } } func main() { //使用newPool构建一个redis连接池 pool := newPool("localhost","32771","123qweasd") defer pool.Close() for i := 0;i <= 4;i++ { go func() { //从pool里面获取一个可用的redis连接 c := pool.Get() defer c.Close() //mset mget fmt.Printf("ActiveCount:%d IdleCount:%d\r\n",pool.Stats().ActiveCount,pool.Stats().IdleCount) _,setErr := c.Do("mset","name","biaoge","url","http://xxbandy.github.io") errCheck("setErr",setErr) if r,mgetErr := redis.Strings(c.Do("mget","name","url")); mgetErr == nil { for _,v := range r { fmt.Println("mget ",v) } } }() } time.Sleep(1*time.Second) }
- golang redis数据库基本操作笔记
- golang学习(二十三):Go操作Redis
- Go语言学习笔记(八)golang 操作 Redis & Mysql & RabbitMQ
- go语言之行--golang操作redis、mysql大全
- Redis数据结构之sds基本操作函数
- Oracle数据库对表数据的基本操作和Oracle字符串、数值、日期、空值操作及它们相对应的函数操作
- Pytohn自定义函数基本操作
- redis基本操作及数据类型命令
- redis的基本操作
- Redis系列-存储篇hash主要操作函数小结
- golang使用go-sql-driver实现mysql增删改操作 推荐
- java对redis的基本操作
- java对redis的基本操作
- 字符串中的一些基本操作函数(c语言)
- 实现基于静态数组的顺序表的以下基本操作(进阶部分)
- ELK研究(一):elasticsearch java api接口操作ES集群 ---TransportClient的使用介绍 bulk批量提交数据
- 三、Redis基本操作——List
- java基本数据类型及其所对应对象的自动装箱,new,valueof操作研究
- python下redis的基本操作:
- java对redis的基本操作