Go使用Redis做缓存

思路

编写config.toml文件作为配置文件,config.go读取配置文件信息,redis.go通过配置信息创建redis连接的数据连接池,main.go使用redis连接测试效果

项目结构

Go使用Redis做缓存_第1张图片

关键代码

  • 读取配置文件
//redis的结构体
type redis struct {
     
	Network string `toml:"network"`
	Address string `toml:"address"`
	Auth    string `toml:"auth"`
}

//初始化Conf信息
func init(){
     
	_,err := toml.DecodeFile(ConfPath,&Conf)//读取配置文件并保存到Conf
	if err != nil {
     
		log.Fatalf("初始化配置信息失败,err={%v}",err)
	}
}
  • 定义缓存接口
type CacheStore interface {
     
	Get(key string,value interface{
     }) error
	Set(key string,value interface{
     },expires time.Duration) error
	Add(key string,value interface{
     },expires time.Duration) error
	Delete(key string) error
	Replace(key string,value interface{
     },expire time.Duration) error
}
  • redis.go实现缓存接口
type RedisStore struct {
     
	pool              *redis.Pool
	defaultExpiration time.Duration
}

//新建RedisStore对象
func NewRedisCache(network string,address string,password string,defaultExpiration time.Duration) *RedisStore {
     
	pool := &redis.Pool{
     
		MaxActive: 512,
		MaxIdle: 10,
		Wait: false,
		IdleTimeout: 3 * time.Second,
		Dial: func() (redis.Conn, error) {
     
			c,err := redis.Dial(network,address)
			if err != nil {
     
				return nil, err
			}
			if len(password) > 0 {
      // 有密码的情况
				if _,err := c.Do("AUTH",password);err != nil{
     
					c.Close()
					return nil,err
				}
			}else {
     // 没有密码的时候 ping 连接
				if _,err := c.Do("ping");err != nil{
     
					c.Close()
					return nil,err
				}
			}
			return c,err
		},
	}
	return &RedisStore{
     pool: pool,defaultExpiration: defaultExpiration}
}

func (c *RedisStore) Get(key string,value interface{
     }) error{
     
	conn := c.pool.Get()
	defer conn.Close()
	reply, err := conn.Do("get", key)
	if err != nil {
     
		return err
	}
	if reply == nil{
     
		return ErrCacheMiss
	}
	bytes, err := redis.Bytes(reply, err)
	return deserialize(bytes,value)//反序列化操作
}
//保存数据
func (c *RedisStore) Set(key string,value interface{
     },expires time.Duration) error{
     
	conn := c.pool.Get()
	defer conn.Close()
	return c.invoke(conn.Do, key, value, expires)
}
//添加数据
func (c *RedisStore) Add(key string,value interface{
     },expires time.Duration) error{
     
	conn := c.pool.Get()
	defer conn.Close()
	b, err := redis.Bool(conn.Do("exists", key))
	if err != nil {
     
		return err
	}
	if b {
      //如果key 已经存在
		return ErrNotStored
	}else {
     
		return c.invoke(conn.Do,key,value,expires)
	}

}
//删除数据
func (c *RedisStore) Delete(key string) error{
     
	conn := c.pool.Get()
	defer conn.Close()
	b, err := redis.Bool(conn.Do("exists", key))
	if err != nil {
     
		return err
	}
	if !b {
      //key值不存在
		return ErrCacheMiss
	}
	_, err2 := conn.Do("del", key)//删除key值
	return err2
}
func (c *RedisStore) Replace(key string,value interface{
     },expires time.Duration) error{
     
	conn := c.pool.Get()
	defer conn.Close()
	b, err := redis.Bool(conn.Do("exists", key))
	if err != nil {
     
		return err
	}
	if !b {
      //key值不存在
		return ErrCacheMiss
	}
	err = c.invoke(conn.Do, key, value, expires)
	if value ==nil {
      //空值不能保存
		return ErrNotStored
	}else {
     
		return err
	}
}

func (c *RedisStore) invoke(f func(string, ...interface{
     }) (interface{
     }, error),
	key string, value interface{
     }, expires time.Duration) error {
     
	b, err := serialize(value)//序列化操作,序列化可以保存对象
	if err != nil {
     
		return err
	}
	if expires > 0 {
     
		_, err := f("setex", key, int32(expires/time.Second), b)
		return err
	} else {
     
		_, err := f("set", key, b)
		return err
	}
}
  • 数据的序列化和反序列化
//序列化
func serialize(value interface{
     }) ([]byte, error) {
     
	if bytes, ok := value.([]byte); ok {
     
		return bytes, nil
	}

	switch v := reflect.ValueOf(value); v.Kind() {
     
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return []byte(strconv.FormatInt(v.Int(), 10)), nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return []byte(strconv.FormatUint(v.Uint(), 10)), nil
	}

	var b bytes.Buffer
	encoder := gob.NewEncoder(&b)
	if err := encoder.Encode(value); err != nil {
     //编码
		return nil, err
	}
	return b.Bytes(), nil
}

//反序列化
func deserialize(byt []byte, ptr interface{
     }) (err error) {
     
	if bytes, ok := ptr.(*[]byte); ok {
     
		*bytes = byt

		return nil
	}

	if v := reflect.ValueOf(ptr); v.Kind() == reflect.Ptr {
      // 通过反射得到ptr类型,判断ptr是指针类型
		switch p := v.Elem(); p.Kind() {
     
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64://符号整型
			var i int64
			i, err = strconv.ParseInt(string(byt), 10, 64)
			if err != nil {
     
				return err
			} else {
     
				p.SetInt(i)
			}
			return nil

		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64://无符号整型
			var i uint64
			i, err = strconv.ParseUint(string(byt), 10, 64)
			if err != nil {
     
				return err
			} else {
     
				p.SetUint(i)
			}
			return nil
		}
	}

	b := bytes.NewBuffer(byt)
	decoder := gob.NewDecoder(b)
	if err = decoder.Decode(ptr); err != nil {
     //解码
		return err
	}
	return nil
}

技术支持
Go使用Redis做缓存_第2张图片

你可能感兴趣的:(redis,golang)