2019-02-02 16:18:25 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-04-18 18:05:46 +08:00
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-04-18 18:05:46 +08:00
|
|
|
|
|
2019-04-02 14:37:46 +08:00
|
|
|
|
// Package gredis provides convenient client for redis server.
|
2019-01-16 13:35:16 +08:00
|
|
|
|
//
|
2018-04-18 18:05:46 +08:00
|
|
|
|
// Redis客户端.
|
2019-04-02 14:37:46 +08:00
|
|
|
|
// Redis中文手册请参考:http://redisdoc.com/
|
|
|
|
|
// Redis官方命令请参考:https://redis.io/commands
|
2018-04-18 18:05:46 +08:00
|
|
|
|
package gredis
|
|
|
|
|
|
|
|
|
|
import (
|
2018-06-05 21:18:41 +08:00
|
|
|
|
"fmt"
|
2019-03-21 00:14:23 +08:00
|
|
|
|
"github.com/gogf/gf/g/container/gmap"
|
|
|
|
|
"github.com/gogf/gf/third/github.com/gomodule/redigo/redis"
|
|
|
|
|
"time"
|
2018-04-18 18:05:46 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2019-03-21 00:14:23 +08:00
|
|
|
|
gDEFAULT_POOL_IDLE_TIMEOUT = 60 * time.Second
|
|
|
|
|
gDEFAULT_POOL_MAX_LIFE_TIME = 60 * time.Second
|
2018-04-18 18:05:46 +08:00
|
|
|
|
)
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// Redis客户端(管理连接池)
|
2018-04-18 18:05:46 +08:00
|
|
|
|
type Redis struct {
|
2019-04-02 14:37:46 +08:00
|
|
|
|
pool *redis.Pool // 底层连接池
|
|
|
|
|
group string // 配置分组
|
|
|
|
|
config Config // 配置对象
|
2018-04-18 18:05:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// Redis连接对象(连接池中的单个连接)
|
|
|
|
|
type Conn redis.Conn
|
|
|
|
|
|
2018-06-05 21:18:41 +08:00
|
|
|
|
// Redis服务端但节点连接配置信息
|
|
|
|
|
type Config struct {
|
2019-03-21 00:14:23 +08:00
|
|
|
|
Host string // 地址
|
|
|
|
|
Port int // 端口
|
|
|
|
|
Db int // 数据库
|
|
|
|
|
Pass string // 授权密码
|
|
|
|
|
MaxIdle int // 最大允许空闲存在的连接数(默认为0表示不存在闲置连接)
|
|
|
|
|
MaxActive int // 最大连接数量限制(默认为0表示不限制)
|
|
|
|
|
IdleTimeout time.Duration // 连接最大空闲时间(默认为60秒,不允许设置为0)
|
|
|
|
|
MaxConnLifetime time.Duration // 连接最长存活时间(默认为60秒,不允许设置为0)
|
2018-06-05 21:18:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-18 18:05:46 +08:00
|
|
|
|
// Redis链接池统计信息
|
|
|
|
|
type PoolStats struct {
|
|
|
|
|
redis.PoolStats
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-02 14:37:46 +08:00
|
|
|
|
var (
|
|
|
|
|
// 单例对象Map
|
2019-05-08 17:21:18 +08:00
|
|
|
|
instances = gmap.NewStrAnyMap()
|
2019-04-02 14:37:46 +08:00
|
|
|
|
// 连接池Map
|
2019-05-08 17:21:18 +08:00
|
|
|
|
pools = gmap.NewStrAnyMap()
|
2019-04-02 14:37:46 +08:00
|
|
|
|
)
|
2018-04-24 23:09:59 +08:00
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// New creates a redis client object with given configuration.
|
|
|
|
|
// Redis client maintains a connection pool automatically.
|
|
|
|
|
//
|
2019-04-02 14:37:46 +08:00
|
|
|
|
// 创建redis操作对象,底层根据配置信息公用的连接池(连接池单例)。
|
2018-06-05 21:18:41 +08:00
|
|
|
|
func New(config Config) *Redis {
|
2019-03-21 00:14:23 +08:00
|
|
|
|
if config.IdleTimeout == 0 {
|
|
|
|
|
config.IdleTimeout = gDEFAULT_POOL_IDLE_TIMEOUT
|
|
|
|
|
}
|
|
|
|
|
if config.MaxConnLifetime == 0 {
|
|
|
|
|
config.MaxConnLifetime = gDEFAULT_POOL_MAX_LIFE_TIME
|
|
|
|
|
}
|
|
|
|
|
return &Redis{
|
2019-03-21 10:04:53 +08:00
|
|
|
|
config : config,
|
|
|
|
|
pool : pools.GetOrSetFuncLock(fmt.Sprintf("%v", config), func() interface{} {
|
2019-03-21 00:14:23 +08:00
|
|
|
|
return &redis.Pool {
|
|
|
|
|
IdleTimeout : config.IdleTimeout,
|
|
|
|
|
MaxConnLifetime : config.MaxConnLifetime,
|
|
|
|
|
Dial : func() (redis.Conn, error) {
|
|
|
|
|
c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", config.Host, config.Port))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// 密码设置
|
|
|
|
|
if len(config.Pass) > 0 {
|
|
|
|
|
if _, err := c.Do("AUTH", config.Pass); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 数据库设置
|
|
|
|
|
if _, err := c.Do("SELECT", config.Db); err != nil {
|
2018-07-05 19:36:35 +08:00
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2019-03-21 00:14:23 +08:00
|
|
|
|
return c, nil
|
|
|
|
|
},
|
2019-03-22 11:22:03 +08:00
|
|
|
|
// 在被应用从连接池中获取出来之后,用以测试连接是否可用,
|
|
|
|
|
// 如果返回error那么关闭该连接对象重新创建新的连接。
|
2019-03-21 00:14:23 +08:00
|
|
|
|
TestOnBorrow: func(c redis.Conn, t time.Time) error {
|
|
|
|
|
_, err := c.Do("PING")
|
|
|
|
|
return err
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}).(*redis.Pool),
|
2018-04-18 18:05:46 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-02 14:37:46 +08:00
|
|
|
|
// Instance returns an instance of redis client with specified group.
|
|
|
|
|
// The <group> param is unnecessary, if <group> is not passed,
|
|
|
|
|
// return redis instance with default group.
|
|
|
|
|
//
|
|
|
|
|
// 获取指定分组名称的Redis单例对象,底层根据配置信息公用的连接池(连接池单例)。
|
2019-04-04 22:52:56 +08:00
|
|
|
|
func Instance(name ...string) *Redis {
|
2019-04-02 14:37:46 +08:00
|
|
|
|
group := DEFAULT_GROUP_NAME
|
|
|
|
|
if len(name) > 0 {
|
|
|
|
|
group = name[0]
|
|
|
|
|
}
|
|
|
|
|
v := instances.GetOrSetFuncLock(group, func() interface{} {
|
|
|
|
|
if config, ok := GetConfig(group); ok {
|
|
|
|
|
r := New(config)
|
|
|
|
|
r.group = group
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
if v != nil {
|
|
|
|
|
return v.(*Redis)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// Close closes the redis connection pool,
|
|
|
|
|
// it will release all connections reserved by this pool.
|
2019-04-02 14:37:46 +08:00
|
|
|
|
// It always not necessary to call Close manually.
|
2019-03-21 00:14:23 +08:00
|
|
|
|
//
|
2019-03-21 10:04:53 +08:00
|
|
|
|
// 关闭redis管理对象,将会关闭底层的连接池。
|
2019-04-02 14:37:46 +08:00
|
|
|
|
// 往往没必要手动调用,跟随进程销毁即可。
|
2018-04-18 18:05:46 +08:00
|
|
|
|
func (r *Redis) Close() error {
|
2019-04-02 14:37:46 +08:00
|
|
|
|
if r.group != "" {
|
|
|
|
|
// 如果是单例对象,那么需要从单例对象Map中删除
|
|
|
|
|
instances.Remove(r.group)
|
|
|
|
|
}
|
2019-03-21 10:04:53 +08:00
|
|
|
|
pools.Remove(fmt.Sprintf("%v", r.config))
|
2018-10-13 21:13:18 +08:00
|
|
|
|
return r.pool.Close()
|
2018-04-18 18:05:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// See GetConn.
|
|
|
|
|
func (r *Redis) Conn() Conn {
|
|
|
|
|
return r.GetConn()
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 10:04:53 +08:00
|
|
|
|
// GetConn returns a raw connection object,
|
|
|
|
|
// which expose more methods communication with server.
|
|
|
|
|
// **You should call Close function manually if you do not use this connection any further.**
|
2019-03-21 00:14:23 +08:00
|
|
|
|
//
|
2018-12-01 11:28:47 +08:00
|
|
|
|
// 获得一个原生的redis连接对象,用于自定义连接操作,
|
|
|
|
|
// 但是需要注意的是如果不再使用该连接对象时,需要手动Close连接,否则会造成连接数超限。
|
2019-03-21 00:14:23 +08:00
|
|
|
|
func (r *Redis) GetConn() Conn {
|
|
|
|
|
return r.pool.Get().(Conn)
|
2018-12-01 11:28:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// SetMaxIdle sets the MaxIdle attribute of the connection pool.
|
|
|
|
|
//
|
2018-04-18 18:05:46 +08:00
|
|
|
|
// 设置属性 - MaxIdle
|
|
|
|
|
func (r *Redis) SetMaxIdle(value int) {
|
|
|
|
|
r.pool.MaxIdle = value
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// SetMaxIdle sets the MaxActive attribute of the connection pool.
|
|
|
|
|
//
|
2018-04-18 18:05:46 +08:00
|
|
|
|
// 设置属性 - MaxActive
|
|
|
|
|
func (r *Redis) SetMaxActive(value int) {
|
|
|
|
|
r.pool.MaxActive = value
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// SetMaxIdle sets the IdleTimeout attribute of the connection pool.
|
|
|
|
|
//
|
2018-04-18 18:05:46 +08:00
|
|
|
|
// 设置属性 - IdleTimeout
|
|
|
|
|
func (r *Redis) SetIdleTimeout(value time.Duration) {
|
|
|
|
|
r.pool.IdleTimeout = value
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// SetMaxIdle sets the MaxConnLifetime attribute of the connection pool.
|
|
|
|
|
//
|
2018-04-18 18:05:46 +08:00
|
|
|
|
// 设置属性 - MaxConnLifetime
|
|
|
|
|
func (r *Redis) SetMaxConnLifetime(value time.Duration) {
|
|
|
|
|
r.pool.MaxConnLifetime = value
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// Stats returns pool's statistics.
|
|
|
|
|
//
|
2019-03-21 10:04:53 +08:00
|
|
|
|
// 获取当前连接池统计信息。
|
2018-04-18 18:05:46 +08:00
|
|
|
|
func (r *Redis) Stats() *PoolStats {
|
|
|
|
|
return &PoolStats{r.pool.Stats()}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// Do sends a command to the server and returns the received reply.
|
2019-03-21 10:04:53 +08:00
|
|
|
|
// Do automatically get a connection from pool, and close it when reply received.
|
2019-03-21 00:14:23 +08:00
|
|
|
|
//
|
2019-03-21 10:04:53 +08:00
|
|
|
|
// 执行同步命令,自动从连接池中获取连接,使用完毕后关闭连接(丢回连接池),开发者不用自行Close.
|
2018-04-18 18:05:46 +08:00
|
|
|
|
func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) {
|
2018-10-13 21:13:18 +08:00
|
|
|
|
conn := r.pool.Get()
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
return conn.Do(command, args...)
|
2018-04-18 18:05:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 23:51:57 +08:00
|
|
|
|
// Deprecated.
|
2019-03-21 00:14:23 +08:00
|
|
|
|
// Send writes the command to the client's output buffer.
|
|
|
|
|
//
|
2018-06-05 21:18:41 +08:00
|
|
|
|
// 执行异步命令 - Send
|
2018-04-18 18:05:46 +08:00
|
|
|
|
func (r *Redis) Send(command string, args ...interface{}) error {
|
2018-10-13 21:13:18 +08:00
|
|
|
|
conn := r.pool.Get()
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
return conn.Send(command, args...)
|
2018-04-18 18:05:46 +08:00
|
|
|
|
}
|
|
|
|
|
|