代码语言:txt复制
git clone https://github.com/ccf19881030/redisgoExample.git
当然运行go项目的前提是需要安装golang开发环境
进入到redisgoExample
目录,执行如下命令:
go mod init ybu.cn/iot
使用go mod init
命令初始化一个ybu.cn/iot
的自定义包
然后同样是在redisgoExample
目录下运行go get
命令安装redisgo
客户端:
go get github.com/gomodule/redigo/redis
此时目录下会多出go.mod
和go.sum
文件,里面包含了redisgo
包的引入。
go.mod
文件内容如下所示:
module ybu.cn/iot
代码语言:txt复制go 1.14
代码语言:txt复制require github.com/gomodule/redigo v1.8.3
go.sum
文件内容如下所示:
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8 OwkZQO4DARzQgrnXU1Liz8=
代码语言:txt复制github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI c5H38=
代码语言:txt复制github.com/gomodule/redigo v1.8.3 h1:HR0kYDX2RJZvAup8CsiJwxB4dTCSC0AaUq6S4SiLwUc=
代码语言:txt复制github.com/gomodule/redigo v1.8.3/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk UUUzlpkBYO0=
代码语言:txt复制github.com/gomodule/redigo/redis v0.0.0-do-not-use h1:J7XIp6Kau0WoyT4JtXHT3Ei0gA1KkSc6bc87j9v9WIo=
代码语言:txt复制github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
代码语言:txt复制github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
代码语言:txt复制github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF rwdDfMAkV7OtwuqBVzrE8GR6GFx wExME=
代码语言:txt复制github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
代码语言:txt复制github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ mT I5cxcmMvtA=
代码语言:txt复制gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
代码语言:txt复制gopkg.in/yaml.v2 v2.2.2 h1:ZCJp EgiOT7lHqUV2J862kp8Qj64Jo6az82 3Td9dZw=
代码语言:txt复制gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm jr3Dg1NNxqwp 5A1VGuI=
自定义的common包
在redisgoExample目录下新建一个common
目录,再创建array.go
、define.go
、interface.go
这三个go文件,用于一些数组、redis配置、redis数据结构的基本操作,
其内容分别如下:
1.array.go
代码语言:txt复制package common
代码语言:txt复制// ArrayOf does the array contain specified item
代码语言:txt复制func ArrayOf(arr []string, dest string) bool {
代码语言:txt复制 for i := 0; i < len(arr); i {
代码语言:txt复制 if arr[i] == dest {
代码语言:txt复制 return true
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 return false
代码语言:txt复制}
代码语言:txt复制// ArrayDuplice 数组去重
代码语言:txt复制func ArrayDuplice(arr []string) []string {
代码语言:txt复制 var out []string
代码语言:txt复制 tmp := make(map[string]byte)
代码语言:txt复制 for _, v := range arr {
代码语言:txt复制 tmplen := len(tmp)
代码语言:txt复制 tmp[v] = 0
代码语言:txt复制 if len(tmp) != tmplen {
代码语言:txt复制 out = append(out, v)
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 return out
代码语言:txt复制}
2.define.go
代码语言:txt复制package common
代码语言:txt复制// RedisConnOpt connect redis options
代码语言:txt复制type RedisConnOpt struct {
代码语言:txt复制 Enable bool
代码语言:txt复制 Host string
代码语言:txt复制 Port int32
代码语言:txt复制 Password string
代码语言:txt复制 Index int32
代码语言:txt复制 TTL int32
代码语言:txt复制}
3.interface.go
代码语言:txt复制package common
代码语言:txt复制// RedisData 存储数据结构
代码语言:txt复制type RedisData struct {
代码语言:txt复制 Key string
代码语言:txt复制 Field string
代码语言:txt复制 Value string
代码语言:txt复制 Expire int64
代码语言:txt复制}
代码语言:txt复制// RedisDataArray RedisData of array
代码语言:txt复制type RedisDataArray []*RedisData
代码语言:txt复制// IRedis redis client interface
代码语言:txt复制type IRedis interface {
代码语言:txt复制 // KEYS get patten key array
代码语言:txt复制 KEYS(patten string) ([]string, error)
代码语言:txt复制 // SCAN get patten key array
代码语言:txt复制 SCAN(patten string) ([]string, error)
代码语言:txt复制 // DEL delete k-v
代码语言:txt复制 DEL(key string) (int, error)
代码语言:txt复制 // DELALL delete key array
代码语言:txt复制 DELALL(key []string) (int, error)
代码语言:txt复制 // GET get k-v
代码语言:txt复制 GET(key string) (string, error)
代码语言:txt复制 // SET set k-v
代码语言:txt复制 //SET(key string, value string) (int64, error)
代码语言:txt复制 // SETEX set k-v expire seconds
代码语言:txt复制 SETEX(key string, sec int, value string) (int64, error)
代码语言:txt复制 // EXPIRE set key expire seconds
代码语言:txt复制 EXPIRE(key string, sec int64) (int64, error)
代码语言:txt复制 // HGETALL get map of key
代码语言:txt复制 HGETALL(key string) (map[string]string, error)
代码语言:txt复制 // HGET get value of key-field
代码语言:txt复制 HGET(key string, field string) (string, error)
代码语言:txt复制 // HSET set value of key-field
代码语言:txt复制 //HSET(key string, field string, value string) (int64, error)
代码语言:txt复制 // Write 向redis中写入多组数据
代码语言:txt复制 Write(data RedisDataArray)
代码语言:txt复制}
redisgo的封装
在redisgoExample目录下新建一个cache目录,在此目录下创建一个redis.go
的文件,主要用于封装常见的redis命令,其内容如下:
package cache
代码语言:txt复制import (
代码语言:txt复制 "fmt"
代码语言:txt复制 "log"
代码语言:txt复制 "time"
代码语言:txt复制 "github.com/gomodule/redigo/redis"
代码语言:txt复制 "ybu.cn/iot/common"
代码语言:txt复制)
代码语言:txt复制// https://godoc.org/github.com/gomodule/redigo/redis#pkg-examples
代码语言:txt复制// https://github.com/gomodule/redigo
代码语言:txt复制// RedisClient redis client instance
代码语言:txt复制type RedisClient struct {
代码语言:txt复制 pool *redis.Pool
代码语言:txt复制 connOpt common.RedisConnOpt
代码语言:txt复制 // 数据接收
代码语言:txt复制 chanRx chan common.RedisDataArray
代码语言:txt复制 // 是否退出
代码语言:txt复制 isExit bool
代码语言:txt复制}
代码语言:txt复制// NewRedis new redis client
代码语言:txt复制func NewRedis(opt common.RedisConnOpt) *RedisClient {
代码语言:txt复制 return &RedisClient{
代码语言:txt复制 connOpt: opt,
代码语言:txt复制 pool: newPool(opt),
代码语言:txt复制 chanRx: make(chan common.RedisDataArray, 100),
代码语言:txt复制 }
代码语言:txt复制}
代码语言:txt复制// newPool 线程池
代码语言:txt复制func newPool(opt common.RedisConnOpt) *redis.Pool {
代码语言:txt复制 return &redis.Pool{
代码语言:txt复制 MaxIdle: 3,
代码语言:txt复制 IdleTimeout: 240 * time.Second,
代码语言:txt复制 // MaxActive: 10,
代码语言:txt复制 // Wait: true,
代码语言:txt复制 Dial: func() (redis.Conn, error) {
代码语言:txt复制 c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", opt.Host, opt.Port))
代码语言:txt复制 if err != nil {
代码语言:txt复制 log.Fatalf("Redis.Dial: %v", err)
代码语言:txt复制 return nil, err
代码语言:txt复制 }
代码语言:txt复制 if _, err := c.Do("AUTH", opt.Password); err != nil {
代码语言:txt复制 c.Close()
代码语言:txt复制 log.Fatalf("Redis.AUTH: %v", err)
代码语言:txt复制 return nil, err
代码语言:txt复制 }
代码语言:txt复制 if _, err := c.Do("SELECT", opt.Index); err != nil {
代码语言:txt复制 c.Close()
代码语言:txt复制 log.Fatalf("Redis.SELECT: %v", err)
代码语言:txt复制 return nil, err
代码语言:txt复制 }
代码语言:txt复制 return c, nil
代码语言:txt复制 },
代码语言:txt复制 }
代码语言:txt复制}
代码语言:txt复制// Start 启动接收任务协程
代码语言:txt复制func (r *RedisClient) Start() {
代码语言:txt复制 r.isExit = false
代码语言:txt复制 // 开启协程用于循环接收数据
代码语言:txt复制 go r.loopRead()
代码语言:txt复制}
代码语言:txt复制// Stop 停止接收任务
代码语言:txt复制func (r *RedisClient) Stop() {
代码语言:txt复制 r.isExit = true
代码语言:txt复制 // 关闭数据接收通道
代码语言:txt复制 close(r.chanRx)
代码语言:txt复制 // 关闭redis线程池
代码语言:txt复制 r.pool.Close()
代码语言:txt复制}
代码语言:txt复制// Write 向redis中写入多组数据
代码语言:txt复制func (r *RedisClient) Write(data common.RedisDataArray) {
代码语言:txt复制 r.chanRx <- data
代码语言:txt复制}
代码语言:txt复制// loopRead 循环接收数据
代码语言:txt复制func (r *RedisClient) loopRead() {
代码语言:txt复制 for !r.isExit {
代码语言:txt复制 select {
代码语言:txt复制 case rx := <-r.chanRx:
代码语言:txt复制 for _, it := range rx {
代码语言:txt复制 if len(it.Key) > 0 {
代码语言:txt复制 if len(it.Field) > 0 {
代码语言:txt复制 if _, err := r.HSET(it.Key, it.Field, it.Value); err != nil {
代码语言:txt复制 log.Printf("[%s, %s, %s]: %sn", it.Key, it.Field, it.Value, err.Error())
代码语言:txt复制 }
代码语言:txt复制 } else {
代码语言:txt复制 if _, err := r.SET(it.Key, it.Value); err != nil {
代码语言:txt复制 log.Printf("[%s, %s, %s]: %sn", it.Key, it.Field, it.Value, err.Error())
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 if it.Expire > 0 {
代码语言:txt复制 r.EXPIRE(it.Key, it.Expire)
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制}
代码语言:txt复制// Error get redis connect error
代码语言:txt复制func (r *RedisClient) Error() error {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return conn.Err()
代码语言:txt复制}
代码语言:txt复制// 常用Redis操作命令的封装
代码语言:txt复制// http://redis.io/commands
代码语言:txt复制// KEYS get patten key array
代码语言:txt复制func (r *RedisClient) KEYS(patten string) ([]string, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.Strings(conn.Do("KEYS", patten))
代码语言:txt复制}
代码语言:txt复制// SCAN 获取大量key
代码语言:txt复制func (r *RedisClient) SCAN(patten string) ([]string, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 var out []string
代码语言:txt复制 var cursor uint64 = 0xffffff
代码语言:txt复制 isfirst := true
代码语言:txt复制 for cursor != 0 {
代码语言:txt复制 if isfirst {
代码语言:txt复制 cursor = 0
代码语言:txt复制 isfirst = false
代码语言:txt复制 }
代码语言:txt复制 arr, err := conn.Do("SCAN", cursor, "MATCH", patten, "COUNT", 100)
代码语言:txt复制 if err != nil {
代码语言:txt复制 return out, err
代码语言:txt复制 }
代码语言:txt复制 switch arr := arr.(type) {
代码语言:txt复制 case []interface{}:
代码语言:txt复制 cursor, _ = redis.Uint64(arr[0], nil)
代码语言:txt复制 it, _ := redis.Strings(arr[1], nil)
代码语言:txt复制 out = append(out, it...)
代码语言:txt复制 }
代码语言:txt复制 }
代码语言:txt复制 out = common.ArrayDuplice(out)
代码语言:txt复制 return out, nil
代码语言:txt复制}
代码语言:txt复制// DEL delete k-v
代码语言:txt复制func (r *RedisClient) DEL(key string) (int, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.Int(conn.Do("DEL", key))
代码语言:txt复制}
代码语言:txt复制// DELALL delete key array
代码语言:txt复制func (r *RedisClient) DELALL(key []string) (int, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 arr := make([]interface{}, len(key))
代码语言:txt复制 for i, v := range key {
代码语言:txt复制 arr[i] = v
代码语言:txt复制 }
代码语言:txt复制 return redis.Int(conn.Do("DEL", arr...))
代码语言:txt复制}
代码语言:txt复制// GET get k-v
代码语言:txt复制func (r *RedisClient) GET(key string) (string, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.String(conn.Do("GET", key))
代码语言:txt复制}
代码语言:txt复制// SET set k-v
代码语言:txt复制func (r *RedisClient) SET(key string, value string) (int64, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.Int64(conn.Do("SET", key, value))
代码语言:txt复制}
代码语言:txt复制// SETEX set k-v expire seconds
代码语言:txt复制func (r *RedisClient) SETEX(key string, sec int, value string) (int64, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.Int64(conn.Do("SETEX", key, sec, value))
代码语言:txt复制}
代码语言:txt复制// EXPIRE set key expire seconds
代码语言:txt复制func (r *RedisClient) EXPIRE(key string, sec int64) (int64, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.Int64(conn.Do("EXPIRE", key, sec))
代码语言:txt复制}
代码语言:txt复制// HGETALL get map of key
代码语言:txt复制func (r *RedisClient) HGETALL(key string) (map[string]string, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.StringMap(conn.Do("HGETALL", key))
代码语言:txt复制}
代码语言:txt复制// HGET get value of key-field
代码语言:txt复制func (r *RedisClient) HGET(key string, field string) (string, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.String(conn.Do("HGET", key, field))
代码语言:txt复制}
代码语言:txt复制// HSET set value of key-field
代码语言:txt复制func (r *RedisClient) HSET(key string, field string, value string) (int64, error) {
代码语言:txt复制 conn := r.pool.Get()
代码语言:txt复制 defer conn.Close()
代码语言:txt复制 return redis.Int64(conn.Do("HSET", key, field, value))
代码语言:txt复制}
测试redis客户端
在redisgoExample目录下新建一个redisgoExample.go
文件用于测试,
其内容如下:
代码语言:txt复制package main
代码语言:txt复制import (
代码语言:txt复制 "fmt"
代码语言:txt复制 "time"
代码语言:txt复制 "ybu.cn/iot/cache"
代码语言:txt复制 "ybu.cn/iot/common"
代码语言:txt复制)
代码语言:txt复制func main() {
代码语言:txt复制 fmt.Println("redisgo client demo")
代码语言:txt复制 // redis的配置
代码语言:txt复制 redisOpt := common.RedisConnOpt{
代码语言:txt复制 true,
代码语言:txt复制 "127.0.0.1",
代码语言:txt复制 6379,
代码语言:txt复制 "123456",
代码语言:txt复制 3,
代码语言:txt复制 240,
代码语言:txt复制 }
代码语言:txt复制 _redisCli := cache.NewRedis(redisOpt)
代码语言:txt复制 // KEYS 示例
代码语言:txt复制 keys, err := _redisCli.KEYS("0_last_gb212_2011:*")
代码语言:txt复制 if err != nil {
代码语言:txt复制 fmt.Println("KEYS failed, err: %v", err)
代码语言:txt复制 }
代码语言:txt复制 for index, val := range keys {
代码语言:txt复制 fmt.Printf("第%d个值为:%sn", index 1, val)
代码语言:txt复制 }
代码语言:txt复制 // GET 示例
代码语言:txt复制 key, err := _redisCli.GET("username")
代码语言:txt复制 if err != nil {
代码语言:txt复制 fmt.Println("GET failed, err: %v", err)
代码语言:txt复制 }
代码语言:txt复制 fmt.Println("key: ", key)
代码语言:txt复制 // SET 示例
代码语言:txt复制 //i1, err := _redisCli.SET("month", "12")
代码语言:txt复制 //if err != nil {
代码语言:txt复制 // fmt.Println("SET failed, err: %v, %v", err, i1)
代码语言:txt复制 //}
代码语言:txt复制 // HGET 示例
代码语言:txt复制 name, err := _redisCli.HGET("animals", "name")
代码语言:txt复制 age, err := _redisCli.HGET("animals", "age")
代码语言:txt复制 sex, err := _redisCli.HGET("animals", "sex")
代码语言:txt复制 color, err := _redisCli.HGET("animals", "color")
代码语言:txt复制 fmt.Printf("animals: [name:%v], [age: %v], [sex: %v], [color: %v]n", name, age, sex, color)
代码语言:txt复制 // HGETALL 示例
代码语言:txt复制 animalsMap, err := _redisCli.HGETALL("animals")
代码语言:txt复制 for k, v := range animalsMap {
代码语言:txt复制 fmt.Printf("k : %v, v: %vt", k, v)
代码语言:txt复制 }
代码语言:txt复制 // redis client
代码语言:txt复制 _redisCli.Start()
代码语言:txt复制 defer _redisCli.Stop()
代码语言:txt复制 t1 := time.Now().UnixNano() / 1e6
代码语言:txt复制 a1, _ := _redisCli.SCAN("GB212_20*")
代码语言:txt复制 t2 := time.Now().UnixNano() / 1e6
代码语言:txt复制 a2, _ := _redisCli.KEYS("GB212_20*")
代码语言:txt复制 t3 := time.Now().UnixNano() / 1e6
代码语言:txt复制 fmt.Printf("SCAN time: %dtlen: %dnKEYS time: %dtlen: %dn", t2-t1, len(a1), t3-t2, len(a2))
代码语言:txt复制}