添加redis 支持

This commit is contained in:
xxj
2021-02-05 20:00:08 +08:00
parent e82090d564
commit d1a0eb2097
11 changed files with 565 additions and 144 deletions

7
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": []
}

View File

@@ -5,5 +5,5 @@ golang 工具包。
包括:
`文件功能`,`leveldb`,`restful风格消息包头定义`,`cache缓存`,`绘图函数`,`elastic`,`echarts`,`http`,`日志`,`nsq抽取`,`线程安全队列`,`签名`,`gorm封装`,`时间函数`,`国际化i18n`,`gocui 界面类`,`驼峰命名转换工具`,`大驼峰到网络标准json串自动转换`,`剪切板`,`微信`,`ast`,`swagger 文档支持`,`mindoc/markdown 文档支持`,`分布式全局唯一id(myglobal)`,`ssh(支持tab自动补全)`,`zap logger`,`快递鸟`
`文件功能`,`leveldb`,`restful风格消息包头定义`,`cache缓存`,`绘图函数`,`elastic`,`echarts`,`http`,`日志`,`nsq抽取`,`线程安全队列`,`签名`,`gorm封装`,`时间函数`,`国际化i18n`,`gocui 界面类`,`驼峰命名转换工具`,`大驼峰到网络标准json串自动转换`,`剪切板`,`微信`,`ast`,`swagger 文档支持`,`mindoc/markdown 文档支持`,`分布式全局唯一id(myglobal)`,`ssh(支持tab自动补全)`,`zap logger`,`快递鸟`,`redis`
......

3
go.mod
View File

@@ -13,7 +13,7 @@ require (
github.com/go-redis/redis/v8 v8.4.11
github.com/go-sql-driver/mysql v1.5.0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/gomodule/redigo v1.8.3 // indirect
github.com/gomodule/redigo v1.8.3
github.com/gookit/color v1.2.5
github.com/jander/golog v0.0.0-20150917071935-954a5be801fc
github.com/jinzhu/gorm v1.9.12
@@ -28,6 +28,7 @@ require (
github.com/nsqio/go-nsq v1.0.8
github.com/olivere/elastic v6.2.31+incompatible
github.com/pkg/errors v0.9.1
github.com/prometheus/common v0.4.0
github.com/spf13/cobra v1.0.0
github.com/syndtr/goleveldb v1.0.0
github.com/xxjwxc/gowp v0.0.0-20200603130651-4d7368b0e285

7
go.sum
View File

@@ -8,7 +8,9 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/ant0ine/go-json-rest v3.3.2+incompatible h1:nBixrkLFiDNAW0hauKDLc8yJI6XfrQumWvytE1Hk14E=
github.com/ant0ine/go-json-rest v3.3.2+incompatible/go.mod h1:q6aCt0GfU6LhpBsnZ/2U+mwe+0XB5WStbmwyoPfc+sk=
@@ -146,6 +148,7 @@ github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYe
github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -207,6 +210,7 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -217,6 +221,7 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -318,6 +323,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -352,6 +358,7 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -7,9 +7,13 @@ import (
"github.com/gomodule/redigo/redis"
)
const KeepTTL = -1
// MyRedis redis配置项
type MyRedis struct {
conf *redisOptions
con redis.Conn
pool *redis.Pool
mtx sync.Mutex
once sync.Once
dial RedisDial
@@ -20,11 +24,12 @@ var _default = &MyRedis{}
// redisOption redisOption
type redisOptions struct {
con redis.Conn
timeout time.Duration
groupName string
pwd string
clientName string
addrs []string
addrIdex int
db int
readTimeout time.Duration
writeTimeout time.Duration

View File

@@ -1,32 +0,0 @@
package myredis
import (
"fmt"
"testing"
"time"
)
func Test_cache(t *testing.T) {
//获取
res, _ := NewRedis([]string{"192.155.1.150:6379"}, "Niren1015", "gggg", 0)
fmt.Println(res.Clear())
aaa := "ccccc"
res.Add("aaaa", aaa, 20*time.Second)
res.Add("bbbb", aaa, 0)
fmt.Println(res.Delete("aaaa"))
fmt.Print(res.IsExist("aaaa"))
var tt string
res.Value("aaaa", &tt)
time.Sleep(20 * time.Second)
fmt.Print(res.IsExist("aaaa"))
fmt.Println(res.Clear())
fmt.Println(tt)
return
}

View File

@@ -1,9 +1,23 @@
package myredis
import "github.com/gomodule/redigo/redis"
import (
"time"
"github.com/gomodule/redigo/redis"
)
// RedisDial 操作
type RedisDial interface {
Destory() // 析构
GetRedisClient() redis.Conn // 获取一个原始的redis连接
Ping() bool // 判断是否能ping通
Add(key interface{}, value interface{}, lifeSpan time.Duration) error // 添加一个元素
Value(key interface{}, value interface{}) error // 获取一个value
IsExist(key interface{}) bool // 判断是否存在
Delete(key interface{}) error // 删除一个
Clear() error // 清空
GetKeyS(key interface{}) ([]string, error) // 查询所有key
Close() (err error) // 关闭连接
}
// DefaultConf ...
@@ -15,7 +29,7 @@ func DefaultConf() *MyRedis {
}
// InitDefaultRedis 初始化(必须要优先调用一次)
func InitDefaultRedis(ops ...Option) {
func InitDefaultRedis(ops ...Option) *MyRedis {
var tmp = &redisOptions{}
for _, o := range ops {
o.apply(tmp)
@@ -27,6 +41,7 @@ func InitDefaultRedis(ops ...Option) {
_default.mtx.Lock()
defer _default.mtx.Unlock()
_default.conf = tmp
return _default
}
// InitRedis 初始化(必须要优先调用一次)
@@ -54,20 +69,28 @@ func NewRedis(con *MyRedis) (dial RedisDial, err error) {
con.once.Do(func() { // 创建连接
ReDialRedis(con)
})
return nil, nil
return con.dial, nil
}
// ReDialRedis 重新连接redis
func ReDialRedis(con *MyRedis) {
if con.dial != nil { // 清理,关闭连接
con.dial.Destory()
}
con.mtx.Lock()
defer con.mtx.Unlock()
if con.conf.maxIdle > 0 { // 创建连接池
if con.conf.maxIdle > 0 { // 创建连接池
con.dial = &redisConPool{
base: base{MyRedis: con},
}
return
}
con.dial =
// 创建单个连接
redis.Dial("tcp",con.)
con.dial = &redisConOlny{
base: base{MyRedis: con},
}
}

44
myredis/myredis_test.go Normal file
View File

@@ -0,0 +1,44 @@
package myredis
import (
"fmt"
"testing"
"time"
)
func Test_cache(t *testing.T) {
conf := InitRedis(WithAddr("192.155.1.150:6379"), WithClientName(""),
// WithPool(2, 2),
WithTimeout(10*time.Second), WithReadTimeout(10*time.Second), WithWriteTimeout(10*time.Second),
WithPwd("Niren1015"), WithGroupName("gggg"), WithDB(0))
//获取
res, err := NewRedis(conf)
fmt.Println(err)
aaa := "ccccc"
res.Add("aaaa", aaa, 20*time.Second)
res.Add("bbbb", aaa, 0)
res.Close()
fmt.Println(res.Ping())
fmt.Print(res.IsExist("aaaa"))
fmt.Print(res.GetKeyS("*"))
fmt.Println(res.Clear())
fmt.Println(res.Delete("aaaa"))
var tt string
res.Value("bbbb", &tt)
var ww []int32
res.Add("cccc", []int32{1, 2, 3, 4}, 0)
res.Value("cccc", &ww)
// time.Sleep(20 * time.Second)
// fmt.Print(res.IsExist("aaaa"))
// fmt.Println(res.Clear())
// fmt.Println(tt)
return
}

View File

@@ -60,3 +60,10 @@ func WithPool(maxIdle, maxActive int) Option {
o.maxActive = maxActive
})
}
// WithClientName 指定Redis服务器连接使用的客户端名称
func WithClientName(name string) Option {
return optionFunc(func(o *redisOptions) {
o.clientName = name
})
}

View File

@@ -1 +1,167 @@
package myredis
import (
"fmt"
"time"
"github.com/gomodule/redigo/redis"
"github.com/xxjwxc/public/mylog"
)
type redisConPool struct {
base
}
func (mc *redisConPool) Destory() {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.con != nil {
err := mc.con.Close()
if err != nil {
mylog.Error(err)
}
mc.con = nil
}
}
func (mc *redisConPool) GetRedisClient() redis.Conn {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.pool == nil { // 创建连接
mc.pool = &redis.Pool{
MaxIdle: mc.conf.maxIdle,
MaxActive: mc.conf.maxActive,
Dial: func() (redis.Conn, error) {
return mc.Dial()
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
if err != nil {
mylog.Errorf("ping redis error: %s", err)
return err
}
return nil
},
}
}
return mc.pool.Get()
}
// Ping 判断是否能ping通
func (mc *redisConPool) Ping() bool {
return mc.ping(mc.GetRedisClient())
}
// Add 添加一个缓存 lifeSpan:缓存时间0表示永不超时
func (mc *redisConPool) Add(key interface{}, value interface{}, lifeSpan time.Duration) error {
var args []interface{}
args = append(args, mc.getKey(key), mc.encodeValue(value))
if lifeSpan > 0 {
if usePrecise(lifeSpan) {
args = append(args, "px", formatMs(lifeSpan))
} else {
args = append(args, "ex", formatSec(lifeSpan))
}
} else if lifeSpan == KeepTTL {
args = append(args, "keepttl")
}
repy, err := mc.Do(mc.GetRedisClient(), "SET", args...)
mylog.Info(redis.String(repy, err))
if err != nil {
mylog.Error(err)
}
return err
}
// Value 查找一个cache
func (mc *redisConPool) Value(key interface{}, value interface{}) (err error) {
repy, err := mc.Do(mc.GetRedisClient(), "GET", mc.getKey(key))
if err != nil {
mylog.Error(err)
return err
}
return mc.decodeValue(repy, value)
}
// IsExist 判断key是否存在
func (mc *redisConPool) IsExist(key interface{}) bool {
repy, err := mc.Do(mc.GetRedisClient(), "EXISTS", mc.getKey(key))
if err != nil {
mylog.Error(err)
return false
}
exist, err := redis.Bool(repy, err) // 转化bool格式
if err != nil {
mylog.Error(err)
return false
}
return exist
}
// Delete 删除一个cache
func (mc *redisConPool) Delete(key interface{}) error {
_, err := mc.Do(mc.GetRedisClient(), "del", mc.getKey(key))
if err != nil {
mylog.Error(err)
return err
}
return err
}
// Clear 清空表內容
func (mc *redisConPool) Clear() error {
out, err := mc.GetKeyS("*")
if err != nil {
return err
}
for _, v := range out {
err = mc.Delete(v)
if err != nil {
return err
}
}
return err
}
// GetKeyS 查询所有key
func (mc *redisConPool) GetKeyS(key interface{}) ([]string, error) {
var keys []string
repy, err := mc.Do(mc.GetRedisClient(), "keys", mc.getKey(key))
if err != nil {
mylog.Error(err)
return keys, err
}
switch t := repy.(type) {
case []interface{}:
for _, v := range t {
out, err := redis.String(v, nil)
if err != nil {
mylog.Error(err)
}
keys = append(keys, mc.fixKeyGroupName(out))
}
default:
return keys, fmt.Errorf("decodeValue err in type not find:%v", t)
}
return keys, err
}
// Close 关闭一个连接
func (mc *redisConPool) Close() (err error) {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.con != nil {
err = mc.con.Close()
mc.con = nil
}
return
}

View File

@@ -3,9 +3,13 @@ package myredis
import (
"context"
"fmt"
"strconv"
"strings"
"time"
"github.com/gomodule/redigo/redis"
"github.com/prometheus/common/log"
"github.com/xxjwxc/public/dev"
"github.com/xxjwxc/public/mylog"
"github.com/xxjwxc/public/tools"
)
@@ -19,157 +23,346 @@ func (mc *base) getCtx() context.Context {
}
func (mc *base) getKey(key interface{}) string {
tmp := ""
if len(mc.conf.groupName) > 0 {
return fmt.Sprintf("%v:%v", mc.conf.groupName, tools.JSONDecode(key))
tmp = fmt.Sprintf("%v:", mc.conf.groupName)
}
switch t := key.(type) {
case []byte:
return fmt.Sprintf("%v%v", tmp, string(t))
case string:
return fmt.Sprintf("%v%v", tmp, t)
default:
return fmt.Sprintf("%v%v", tmp, tools.JSONDecode(key))
}
return tools.JSONDecode(key)
}
func initConOlny(cnf *MyRedis) *redisConOlny {
return &redisConOlny{
base: base{MyRedis: cnf},
func (mc *base) encodeValue(value interface{}) interface{} {
switch t := value.(type) {
case int32, byte, string, bool, int, uint, int8, int16, int64, uint16, uint32, uint64, float32, float64: // 基础类型
return t
default:
return tools.JSONDecode(value)
// data, _ := serializing.Encode(value)
// return data
}
}
func (mc *base) decodeValue(in, out interface{}) (err error) {
if in == nil {
return fmt.Errorf("not fond")
}
var reply string
switch t := in.(type) {
case []byte:
reply = string(t)
default:
return fmt.Errorf("decodeValue err in type not find:%v", t)
}
switch o := out.(type) {
case *string: // string类型
*o = reply
return nil
case *int32:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int32(i64)
return err
case *bool:
b, err := strconv.ParseBool(string(reply))
*o = b
return err
case *int:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int(i64)
return err
case *int8:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int8(i64)
return err
case *int16:
i64, err := strconv.ParseInt(reply, 10, 0)
*o = int16(i64)
return err
case *int64:
i64, err := strconv.ParseInt(string(reply), 10, 64)
*o = int64(i64)
return err
case *uint:
i64, err := strconv.ParseUint(reply, 10, 0)
*o = uint(i64)
return err
case *uint8:
i64, err := strconv.ParseUint(reply, 10, 0)
*o = uint8(i64)
return err
case *uint16:
i64, err := strconv.ParseUint(reply, 10, 0)
*o = uint16(i64)
return err
case *uint32:
i64, err := strconv.ParseInt(string(reply), 10, 0)
*o = uint32(i64)
return err
case *uint64:
i64, err := strconv.ParseUint(reply, 10, 64)
*o = uint64(i64)
return err
case *float32:
f64, err := strconv.ParseFloat(string(reply), 32)
*o = float32(f64)
return err
case *float64: // 基础类型
f64, err := strconv.ParseFloat(string(reply), 64)
*o = float64(f64)
return err
default:
tools.JSONEncode(reply, out) // 复杂类型
return nil
//return serializing.Decode(t, out)
}
// return fmt.Errorf("decodeValue err not match:%v %v", in, out)
}
func (mc *base) ping(con redis.Conn) bool {
if con == nil {
return false
}
_, err := con.Do("PING")
if err != nil {
mylog.Errorf("ping redis error: %s", err)
return false
}
return true
}
// Dial 获取一个链接
func (mc *base) Dial() (redis.Conn, error) {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.con == nil { // 创建连接
index := mc.conf.addrIdex
len := len(mc.conf.addrs)
b := false
var err error
for i := 0; i < len; i++ {
index = (mc.conf.addrIdex + i) % len
mc.con, err = redis.Dial("tcp", mc.conf.addrs[index], redis.DialClientName(mc.conf.clientName),
redis.DialConnectTimeout(mc.conf.timeout), redis.DialDatabase(mc.conf.db),
redis.DialPassword(mc.conf.pwd), redis.DialReadTimeout(mc.conf.readTimeout), redis.DialWriteTimeout(mc.conf.writeTimeout),
)
if err != nil {
mylog.Error(err)
}
if mc.ping(mc.con) {
b = true
}
}
if b {
mc.conf.addrIdex = (index + 1) % len
}
return mc.con, err
}
return mc.con, nil
}
func (mc *base) Do(con redis.Conn, commandName string, args ...interface{}) (reply interface{}, err error) {
if dev.IsDev() {
cmd := commandName
for _, v := range args {
cmd += fmt.Sprintf(" %v", v)
}
log.Infof("redis req :%v", cmd)
}
if con != nil {
reply, err = con.Do(commandName, args...)
// show log
if dev.IsDev() {
tmp := ""
switch reply := reply.(type) {
case []byte:
tmp = string(reply)
case string:
tmp = reply
case int64:
tmp = fmt.Sprintf("%v", reply)
}
log.Infof("redis resp:%v,%v", tmp, err)
}
return
}
return nil, fmt.Errorf("con is nil")
}
func (mc *base) fixKeyGroupName(key string) string {
tmp := ""
if len(mc.conf.groupName) > 0 {
tmp = fmt.Sprintf("%v:", mc.conf.groupName)
}
return strings.TrimPrefix(key, tmp)
}
type redisConOlny struct {
base
}
// NewRedis 初始化一个cache cachename 缓存名字
func NewRedis(addrs []string, pwd, groupName string, timeout time.Duration) (mc *MyRedis, err error) {
redis.Dial()
redis.SetLogger(&logger{})
if len(addrs) <= 1 {
mc = &MyRedis{
Cmdable: redis.NewClient(&redis.Options{
Addr: addrs[0],
DialTimeout: timeout,
Password: pwd, // no password set
// DB: 0, // use default DB
}),
}
} else {
mc = &MyRedis{
Cmdable: redis.NewClusterClient(&redis.ClusterOptions{
Addrs: addrs,
Password: pwd, // no password set
DialTimeout: timeout,
}),
// Destory 析构
func (mc *redisConOlny) Destory() {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.con != nil {
err := mc.con.Close()
if err != nil {
mylog.Error(err)
}
mc.con = nil
}
mc.timeout = timeout
mc.groupName = groupName
err = mc.Ping(mc.getCtx()).Err()
if err != nil {
mylog.Error(err)
}
return
}
func (mc *MyRedis) getCtx() context.Context {
return context.Background()
// GetRedisClient ...
func (mc *redisConOlny) GetRedisClient() redis.Conn {
con, _ := mc.Dial()
return con
}
func (mc *MyRedis) getKey(key interface{}) string {
if len(mc.groupName) > 0 {
return fmt.Sprintf("%v:%v", mc.groupName, tools.JSONDecode(key))
}
return tools.JSONDecode(key)
// Ping 判断是否能ping通
func (mc *redisConOlny) Ping() bool {
return mc.ping(mc.GetRedisClient())
}
// 判断是否能ping通
// Add 添加一个缓存 lifeSpan:缓存时间0表示永不超时
func (mc *MyRedis) Add(key interface{}, value interface{}, lifeSpan time.Duration) (err error) {
set := mc.Set(mc.getCtx(), mc.getKey(key), tools.JSONDecode(value), lifeSpan)
mylog.Info(set.Val())
// redis.Expect(set.Err()).NotTo(HaveOccurred())
// redis.Expect(set.Val()).To(Equal("OK"))
err = set.Err()
func (mc *redisConOlny) Add(key interface{}, value interface{}, lifeSpan time.Duration) error {
var args []interface{}
args = append(args, mc.getKey(key), mc.encodeValue(value))
if lifeSpan > 0 {
if usePrecise(lifeSpan) {
args = append(args, "px", formatMs(lifeSpan))
} else {
args = append(args, "ex", formatSec(lifeSpan))
}
} else if lifeSpan == KeepTTL {
args = append(args, "keepttl")
}
_, err := mc.Do(mc.GetRedisClient(), "SET", args...)
if err != nil {
mylog.Error(err)
}
return
return err
}
// Value 查找一个cache
func (mc *MyRedis) Value(key interface{}, value interface{}) (err error) {
set := mc.Get(mc.getCtx(), mc.getKey(key))
mylog.Info(set.Val())
// redis.Expect(set.Err()).NotTo(HaveOccurred())
// redis.Expect(set.Val()).To(Equal("OK"))
err = set.Err()
func (mc *redisConOlny) Value(key interface{}, value interface{}) (err error) {
repy, err := mc.Do(mc.GetRedisClient(), "GET", mc.getKey(key))
if err != nil {
mylog.Error(err)
return
return err
}
tools.JSONEncode(set.Val(), value)
return
return mc.decodeValue(repy, value)
}
// IsExist 判断key是否存在
func (mc *MyRedis) IsExist(key interface{}) bool {
set := mc.Exists(mc.getCtx(), mc.getKey(key))
mylog.Info(set.Val())
// redis.Expect(set.Err()).NotTo(HaveOccurred())
// redis.Expect(set.Val()).To(Equal("OK"))
err := set.Err()
func (mc *redisConOlny) IsExist(key interface{}) bool {
repy, err := mc.Do(mc.GetRedisClient(), "EXISTS", mc.getKey(key))
if err != nil {
mylog.Error(err)
return false
}
exist, err := redis.Bool(repy, err) // 转化bool格式
if err != nil {
mylog.Error(err)
return false
}
return set.Val() == 1
return exist
}
// Delete 删除一个cache
func (mc *MyRedis) Delete(key interface{}) error {
set := mc.Del(mc.getCtx(), mc.getKey(key))
mylog.Info(set.Val())
// redis.Expect(set.Err()).NotTo(HaveOccurred())
// redis.Expect(set.Val()).To(Equal("OK"))
err := set.Err()
func (mc *redisConOlny) Delete(key interface{}) error {
_, err := mc.Do(mc.GetRedisClient(), "del", mc.getKey(key))
if err != nil {
mylog.Error(err)
return err
}
return err
}
// GetRedisClient 获取原始cache2go操作类
func (mc *MyRedis) GetRedisClient() redis.Cmdable {
return mc
}
// Clear 清空表內容
func (mc *MyRedis) Clear() error {
key := "*"
if len(mc.groupName) > 0 {
key = fmt.Sprintf("%v:*", mc.groupName)
func (mc *redisConOlny) Clear() error {
out, err := mc.GetKeyS("*")
if err != nil {
return err
}
set := mc.Pipeline().Do(mc.getCtx(), "KEYS", key)
mylog.Info(set.Val())
// redis.Expect(set.Err()).NotTo(HaveOccurred())
// redis.Expect(set.Val()).To(Equal("OK"))
err := set.Err()
if err != nil {
mylog.Error(err)
}
return mc.delete(key)
}
// delete 删除一个cache
func (mc *MyRedis) delete(key string) error {
set := mc.Del(mc.getCtx(), key)
mylog.Info(set.Val())
// redis.Expect(set.Err()).NotTo(HaveOccurred())
// redis.Expect(set.Val()).To(Equal("OK"))
err := set.Err()
if err != nil {
mylog.Error(err)
for _, v := range out {
err = mc.Delete(v)
if err != nil {
return err
}
}
return err
}
// GetKeyS 查询所有key
func (mc *redisConOlny) GetKeyS(key interface{}) ([]string, error) {
var keys []string
repy, err := mc.Do(mc.GetRedisClient(), "keys", mc.getKey(key))
if err != nil {
mylog.Error(err)
return keys, err
}
switch t := repy.(type) {
case []interface{}:
for _, v := range t {
out, err := redis.String(v, nil)
if err != nil {
mylog.Error(err)
}
keys = append(keys, mc.fixKeyGroupName(out))
}
default:
return keys, fmt.Errorf("decodeValue err in type not find:%v", t)
}
return keys, err
}
// Close 关闭一个连接
func (mc *redisConOlny) Close() (err error) {
mc.mtx.Lock()
defer mc.mtx.Unlock()
if mc.con != nil {
err = mc.con.Close()
mc.con = nil
}
return
}
func usePrecise(dur time.Duration) bool {
return dur < time.Second || dur%time.Second != 0
}
func formatMs(dur time.Duration) int64 {
if dur > 0 && dur < time.Millisecond {
return 1
}
return int64(dur / time.Millisecond)
}
func formatSec(dur time.Duration) int64 {
if dur > 0 && dur < time.Second {
return 1
}
return int64(dur / time.Second)
}