package redis import ( "fmt" "git.shuncheng.lu/bigthing/gocommon/pkg/conf" "git.shuncheng.lu/bigthing/gocommon/pkg/internal/util" "git.shuncheng.lu/bigthing/gocommon/pkg/logger" "git.shuncheng.lu/bigthing/gocommon/pkg/net/qconf" "github.com/garyburd/redigo/redis" ) var ( redisInstance *ConnPool ) // ConnPool is for Cache fd type ConnPool struct { prefix string redisPool *redis.Pool } //获取实例 func Instance() *ConnPool { return redisInstance } // 将Pool暴露出去,记住需要defer close! func InstancePool() *redis.Pool { return redisInstance.redisPool } func PrefixKey(key string) string { return fmt.Sprintf("%s%s", redisInstance.prefix, key) } func CheckIsNilErr(err error) bool { // 检测是不是nil的问题,true是nil-err return err == redis.ErrNil } func CheckIsNotNilErr(err error) bool { // 检测是不是nil的问题,true不是nil-err return err != redis.ErrNil } func getConfig(section, key string, defaultVal ...string) string { return conf.GetString(section, key, defaultVal...) } //初始化redis pool func Init() error { config, err := getRedisConfig("redis", conf.SetAndAssertNil) if err != nil { return err } util.Debugf("Redis load config success, config=%+v", config) redisConfig := getRedisConfigFromMap(config) // 如果不是直接连接&&env不是debug则qconf获取 if (!util.String2Bool(config["is_direct"])) && conf.GetEnv() != conf.EnvDebug { realHost, err := qconf.GetHost(redisConfig.Host, qconf.GetQconfIdc()) if err != nil { return err } redisConfig.Host = realHost } pool, err := newRedisPool(redisConfig) if err != nil { return err } redisInstance = &ConnPool{redisPool: pool, prefix: config["cache_prefix"]} return nil } // Close pool func (p *ConnPool) Close() error { err := p.redisPool.Close() return err } // Do commands func (p *ConnPool) Do(command string, args ...interface{}) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return conn.Do(command, args...) } // SetString for string func (p *ConnPool) SetString(key string, value interface{}) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return conn.Do("SET", key, value) } // SetString for string ttl,ttl 单位s func (p *ConnPool) SetExString(key string, value interface{}, ttl uint64) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return conn.Do("SET", key, value, "EX", ttl) } // GetString for string, 如果key不存在会抛出异常: redigo: nil returned func (p *ConnPool) GetString(key string) (string, error) { // get one connection from pool conn := p.redisPool.Get() // put connection to pool defer conn.Close() return redis.String(conn.Do("GET", key)) } // GetBytes for bytes func (p *ConnPool) GetBytes(key string) ([]byte, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Bytes(conn.Do("GET", key)) // if nil return errnil } // GetInt for int func (p *ConnPool) GetInt(key string) (int, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Int(conn.Do("GET", key)) } //Incr func (p *ConnPool) Incr(key string) (int, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Int(conn.Do("INCR", key)) } //Decr func (p *ConnPool) Decr(key string) (int, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Int(conn.Do("DECR", key)) } // GetInt64 for int64 func (p *ConnPool) GetInt64(key string) (int64, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Int64(conn.Do("GET", key)) } // DelKey for key func (p *ConnPool) DelKey(key string) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return conn.Do("DEL", key) } // ExpireKey for key func (p *ConnPool) ExpireKey(key string, seconds int64) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return conn.Do("EXPIRE", key, seconds) } // Keys for key func (p *ConnPool) Keys(pattern string) ([]string, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Strings(conn.Do("KEYS", pattern)) } // KeysByteSlices for key func (p *ConnPool) KeysByteSlices(pattern string) ([][]byte, error) { conn := p.redisPool.Get() defer conn.Close() return redis.ByteSlices(conn.Do("KEYS", pattern)) } // SetHashMap for hash map func (p *ConnPool) SetHashMap(key string, fieldValue map[string]interface{}) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return conn.Do("HMSET", redis.Args{}.Add(key).AddFlat(fieldValue)...) } // GetHashMapString for hash map func (p *ConnPool) GetHashMapString(key string) (map[string]string, error) { conn := p.redisPool.Get() defer conn.Close() return redis.StringMap(conn.Do("HGETALL", key)) } // HGet func (p *ConnPool) HGet(key, field string) (string, error) { conn := p.redisPool.Get() defer conn.Close() return redis.String(conn.Do("HGET", key, field)) } // HSet func (p *ConnPool) HSet(key, field, val string) (int, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Int(conn.Do("HSET", key, field, val)) } // GetHashMapInt for hash map func (p *ConnPool) GetHashMapInt(key string) (map[string]int, error) { conn := p.redisPool.Get() defer conn.Close() return redis.IntMap(conn.Do("HGETALL", key)) } // GetHashMapInt64 for hash map func (p *ConnPool) GetHashMapInt64(key string) (map[string]int64, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Int64Map(conn.Do("HGETALL", key)) } // LPUSH func (p *ConnPool) LPUSH(key string, fieldValue []interface{}) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return conn.Do("LPUSH", redis.Args{}.Add(key).AddFlat(fieldValue)...) } // LPOP func (p *ConnPool) LPOP(key string) (interface{}, error) { conn := p.redisPool.Get() defer conn.Close() return redis.String(conn.Do("LPOP", key)) } // BLPOP func (p *ConnPool) BLPOP(key string, timeout int) ([]string, error) { conn := p.redisPool.Get() defer conn.Close() return redis.Strings(conn.Do("BLPOP", key, timeout)) } /* Distributed mutual exclusion lock(Redis分布式排斥锁) */ //===========start=========== func (p *ConnPool) LockAcquire(name string, value string, expiry int) bool { conn := p.redisPool.Get() defer conn.Close() reply, err := redis.String(conn.Do("SET", name, value, "NX", "PX", expiry)) logger.Infof("Redis LockAcquire name:%s,value:%s,reply:%s", name, value, reply) return err == nil && reply == "OK" } var lockDeleteScript = redis.NewScript(1, ` if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end `) func (p *ConnPool) LockRelease(name string, value string) bool { conn := p.redisPool.Get() defer conn.Close() status, err := lockDeleteScript.Do(conn, name, value) return err == nil && status != 0 } var lockTouchScript = redis.NewScript(1, ` if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("SET", KEYS[1], ARGV[1], "XX", "PX", ARGV[2]) else return "ERR" end `) func (p *ConnPool) LockTouch(name string, value string, expiry int) bool { conn := p.redisPool.Get() defer conn.Close() status, err := redis.String(lockTouchScript.Do(conn, name, value, expiry)) return err == nil && status != "ERR" } //===========end===========