【Go】go-redis使用手记

皇甫伟彦
2023-12-01

redis初始化

func RedisInit() *redis.Client {
	var rdb = redis.NewClient(&redis.Options{Addr: "x.x.x.x:6379", Password: "xxxxxx", DB: 6,
		//连接池容量及闲置连接数量
		//go-redis包自带了连接池,会自动维护redis连接,因此创建一次client即可,不要查询一次redis就关闭client。
		//PoolSize:     15, // 连接池最大socket连接数,默认为4倍CPU数, 4 * runtime.NumCPU
		//MinIdleConns: 10, //在启动阶段创建指定数量的Idle连接,并长期维持idle状态的连接数不少于指定数量;。
		//超时
		DialTimeout:  5 * time.Second, //连接建立超时时间,默认5秒。
		ReadTimeout:  3 * time.Second, //读超时,默认3秒, -1表示取消读超时
		WriteTimeout: 3 * time.Second, //写超时,默认等于读超时
		PoolTimeout:  4 * time.Second, //当所有连接都处在繁忙状态时,客户端等待可用连接的最大等待时长,默认为读超时+1秒。
		//闲置连接检查包括IdleTimeout,MaxConnAge
		IdleCheckFrequency: 60 * time.Second, //闲置连接检查的周期,默认为1分钟,-1表示不做周期性检查,只在客户端获取连接时对闲置连接进行处理。
		IdleTimeout:        5 * time.Minute,  //闲置超时,默认5分钟,-1表示取消闲置超时检查
		MaxConnAge:         0 * time.Second,  //连接存活时长,从创建开始计时,超过指定时长则关闭连接,默认为0,即不关闭存活时长较长的连接
		//命令执行失败时的重试策略
		MaxRetries:      0,                      // 命令执行失败时,最多重试多少次,默认为0即不重试
		MinRetryBackoff: 8 * time.Millisecond,   //每次计算重试间隔时间的下限,默认8毫秒,-1表示取消间隔
		MaxRetryBackoff: 512 * time.Millisecond, //每次计算重试间隔时间的上限,默认512毫秒,-1表示取消间隔
		//可自定义连接函数
		Dialer: func() (net.Conn, error) {
			netDialer := &net.Dialer{
				Timeout:   5 * time.Second,
				KeepAlive: 5 * time.Minute,
			}
			return netDialer.Dial("tcp", "x.x.x.x:6379")
		},
		//钩子函数
		OnConnect: func(conn *redis.Conn) error { //仅当客户端执行命令时需要从连接池获取连接时,如果连接池需要新建连接时则会调用此钩子函数
			fmt.Printf("redis从连接池获取链接%v\n", conn)
			return nil
		},
	})
	res, err := rdb.Ping().Result()
	if err != nil {
		fmt.Println("ping 出错:", err)
	}
	fmt.Println("redis:" + res)
	//工具
	utils.SetRDB(rdb)
	return rdb
}

	//defer func(rdb *redis.Client) {
	//	err := rdb.Close()
	//	if err != nil {
	//		log.Fatal(err)
	//	}
	//}(rdb)

redis工具部分封装

package utils

import (
	"github.com/go-redis/redis"
	"log"
	"time"
)

var rdb *redis.Client

func SetRDB(r *redis.Client) {
	rdb = r
}

func GetRDB() *redis.Client {
	return rdb
}

func Exists(keys ...string) bool {
	result, err := rdb.Exists(keys...).Result()
	if err != nil {
		log.Fatal(err)
		return false
	}
	return result == 1
}

// Expire 设置key的过期时间
func Expire(key string, expiration int) {
	rdb.Expire(key, time.Duration(expiration)*time.Second)
}

func Keys(pattern string) ([]string, error) {
	return rdb.Keys(pattern).Result()
}

// Set : expiration=0表示无过期时间
func Set(key string, value any, expiration int) {
	err := rdb.Set(key, value, time.Duration(expiration)*time.Second).Err()
	if err != nil {
		panic(err)
	}
}

func Get(key string) (string, error) {
	return rdb.Get(key).Result()
}

func Del(keys ...string) bool {
	result, err := rdb.Del(keys...).Result()
	if err != nil {
		return false
	}
	return result == 1
}

// SetIfAbsent 不存在时才设置(新增操作)SetNX
func SetIfAbsent(key string, value any, expiration int) bool {
	result, err := rdb.SetNX(key, value, time.Duration(expiration)*time.Second).Result()
	if err != nil {
		log.Fatal(err)
		return false
	} // name存在,不会修改
	return result
}

// SetIfPresent 存在时才设置(修改操作)SetXX
func SetIfPresent(key string, value any, expiration int) bool {
	result, err := rdb.SetXX(key, value, time.Duration(expiration)*time.Second).Result()
	if err != nil {
		log.Fatal(err)
		return false
	}
	return result
}

// Incr Incr函数每次加一
func Incr(key string) int64 {
	result, err := rdb.Incr(key).Result()
	if err != nil {
		panic(err)
	}
	return result
}

func IncrBy(key string, value int64) int64 {
	result, err := rdb.IncrBy(key, value).Result()
	if err != nil {
		panic(err)
	}
	return result
}

func IncrByFloat(key string, value float64) float64 {
	result, err := rdb.IncrByFloat(key, value).Result()
	if err != nil {
		panic(err)
	}
	return result
}

func Decr(key string) int64 {
	result, err := rdb.Decr(key).Result()
	if err != nil {
		panic(err)
	}
	return result
}

func DecrBy(key string, value int64) int64 {
	result, err := rdb.DecrBy(key, value).Result()
	if err != nil {
		panic(err)
	}
	return result
}

// MGet MGet函数可以传入任意个key,一次性返回多个值。
// 这里Result返回两个值,第一个值是一个数组,第二个值是错误信息
func MGet(keys ...string) []interface{} {
	result, err := rdb.MGet(keys...).Result()
	if err != nil {
		log.Fatal(err)
		return nil
	}
	return result
}

func StrLen(key string) (int64, error) {
	return rdb.StrLen("name").Result()
}

// RPush 列表右侧插入o(1~n)
func RPush(key string, value any) {
	rdb.RPush(key, value)
}

// LPush 列表左侧插入
func LPush(key string, value any) {
	rdb.LPush(key, value)
}

// LInsertBefore #从元素value前插入newValue 时间复杂度o(n) ,需要遍历列表
func LInsertBefore(key string, pivot, value any) {
	rdb.LInsertBefore(key, pivot, value)
}

// LInsertAfter #从元素value后插入newValue 时间复杂度o(n) ,需要遍历列表
func LInsertAfter(key string, pivot, value any) {
	rdb.LInsertAfter(key, pivot, value)
}

// LPop 从列表左侧弹出一个item 时间复杂度o(1)
func LPop(key string) (string, error) {
	return rdb.LPop(key).Result()

}

// RPop 从列表右侧弹出一个item 时间复杂度o(1)
func RPop(key string) (string, error) {
	return rdb.RPop(key).Result()
}

// LRem 根据count值,从列表中删除所有value相同的项 时间复杂度o(n)
// 1 count>0 从左到右,删除最多count个value相等的项
// 2 count<0 从右向左,删除最多 Math.abs(count)个value相等的项
// 3 count=0 删除所有value相等的项
func LRem(key string, count int64, value any) {
	rdb.LRem(key, count, value)
}

// LTrim 按照索引范围修剪列表 o(n),保留开始到结束范围
func LTrim(key string, start, stop int64) {
	rdb.LTrim(key, start, stop)
}

// LRange 包含stop获取列表指定索引范围所有item  o(n) 从start到stop
func LRange(key string, start, stop int64) ([]string, error) {
	return rdb.LRange(key, start, stop).Result()
}

// LIndex 获取列表指定索引的item  o(n)
func LIndex(key string, index int64) (string, error) {
	return rdb.LIndex(key, index).Result()
}

// LLen 获取列表长度
func LLen(key string) (int64, error) {
	return rdb.LLen(key).Result()
}

// LSet 设置列表指定索引值为value o(n)
func LSet(key string, index int64, value interface{}) {
	rdb.LSet(key, index, value)
}

// HGet 获取hash key对应的field的value 时间复杂度为 o(1)
func HGet(key, field string) (string, error) {
	return rdb.HGet(key, field).Result()
}

// HGetAll 返回hash key 对应的所有field和value  时间复杂度是o(n)
func HGetAll(key string) (map[string]string, error) {
	return rdb.HGetAll(key).Result()
}

// HVals 返回hash key 对应的所有field的value  时间复杂度是o(n)
func HVals(key string) ([]string, error) {
	return rdb.HVals(key).Result()
}

// HKeys 返回hash key对应的所有field  时间复杂度是o(n)
func HKeys(key string) ([]string, error) {
	return rdb.HKeys(key).Result()
}

func HIncrBy(key, field string, incr int64) (int64, error) {
	return rdb.HIncrBy(key, field, incr).Result()
}

// HSet 设置hash key对应的field的value值 时间复杂度为 o(1)
func HSet(key, field string, value interface{}) {
	rdb.HSet(key, field, value)
}

// HDel 删除hash key对应的field的值 时间复杂度为 o(1)
func HDel(key string, fields ...string) {
	rdb.HDel(key, fields...)
}

func HExists(key, field string) bool {
	result, err := rdb.HExists(key, field).Result()
	if err != nil {
		log.Fatal(err)
		return false
	}
	return result
}

// HLen 获取hash key field的数量  时间复杂度为 o(1)
func HLen(key string) (int64, error) {
	return rdb.HLen(key).Result()
}

// HMGet 批量获取hash key 的一批field对应的值  时间复杂度是o(n)
func HMGet(key string, fields ...string) ([]interface{}, error) {
	return rdb.HMGet(key, fields...).Result()
}

// HMSet 批量设置hash key的一批field value 时间复杂度是o(n)
func HMSet(key string, fields map[string]interface{}) {
	rdb.HMSet(key, fields)
}

// SAdd 向集合key添加element(如果element存在,添加失败) o(1)
func SAdd(key string, members ...interface{}) {
	rdb.SAdd(key, members...)
}

// SRem 从集合中的element移除掉 o(1)
func SRem(key string, members ...interface{}) {
	rdb.SRem(key, members...)
}

// SCard 计算集合大小
func SCard(key string) (int64, error) {
	return rdb.SCard(key).Result()
}

// SIsMember 判断element是否在集合中
func SIsMember(key string, member interface{}) bool {
	result, err := rdb.SIsMember(key, member).Result()
	if err != nil {
		log.Fatal(err)
		return false
	}
	return result
}


// Subscribe 订阅消息
// // 读取channel消息
// iface, err := sub.Receive()
//
//	if err != nil {
//	   // handle error
//	}
//
// // 检测收到的消息类型
// switch iface.(type) {
// case *redis.Subscription:
//
//	// 订阅成功
//
// case *redis.Message:
//
//	   // 处理收到的消息
//	   // 这里需要做一下类型转换
//	   m := iface.(redis.Message)
//	   // 打印收到的消息
//		fmt.Println(m.Payload)
//
// case *redis.Pong:
//
//	// 收到Pong消息
//
// default:
//
//	// handle error
//
// //sub.Channel() 返回go channel,可以循环读取redis服务器发过来的消息
//
// for msg := range sub.Channel() {
//
// // 打印收到的消息
//
// fmt.Println(msg.Channel)
//
// fmt.Println(msg.Payload)
// }
// // 取消订阅
//
// sub.Unsubscribe("channel1")
func Subscribe(channels ...string) *redis.PubSub {
	return rdb.Subscribe(channels...)
}

// PSubscribe 用法跟Subscribe一样,区别是PSubscribe订阅通道(channel)支持模式匹配。
func PSubscribe(channels ...string) *redis.PubSub {
	return rdb.PSubscribe(channels...)
}

// Publish 将消息发送到指定的channel
func Publish(channel string, message interface{}) {
	err := rdb.Publish(channel, message).Err()
	if err != nil {
		panic(err)
	}
}

// PubSubChannels 查询活跃的channel
// pattern "user_*"
func PubSubChannels(pattern string) []string {
	// 没有指定查询channel的匹配模式,则返回所有的channel
	chs, err := rdb.PubSubChannels(pattern).Result()
	if err != nil {
		panic(err)
	}
	return chs
}

// PubSubNumSub 查询指定的channel有多少个订阅者
//
//	for ch, count := range chs {
//		fmt.Println(ch) // channel名字
//		fmt.Println(count) // channel的订阅者数量
//	}
func PubSubNumSub(channels ...string) map[string]int64 {
	chs, err := rdb.PubSubNumSub(channels...).Result()
	if err != nil {
		panic(err)
	}
	return chs
}

// TxPipeline 以Pipeline的方式操作事务
//
// // 通过Exec函数提交redis事务
//
// _, err := pipe.Exec()
func TxPipeline() redis.Pipeliner {
	return rdb.TxPipeline()
}

// Watch redis乐观锁支持,可以通过watch监听一些Key, 如果这些key的值没有被其他人改变的话,才可以提交事务。
// // 定义一个回调函数,用于处理事务逻辑
//
//	fn := func(tx *redis.Tx) error {
//			// 先查询下当前watch监听的key的值
//			v, err := tx.Get("key").Result()
//			if err != nil && err != redis.Nil {
//				return err
//			}
//
//			// 这里可以处理业务
//			fmt.Println(v)
//
//			// 如果key的值没有改变的话,Pipelined函数才会调用成功
//			_, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
//				// 在这里给key设置最新值
//				pipe.Set("key", "new value", 0)
//				return nil
//			})
//			return err
//		}
//
// // 使用Watch监听一些Key, 同时绑定一个回调函数fn, 监听Key后的逻辑写在fn这个回调函数里面
// // 如果想监听多个key,可以这么写:client.Watch(fn, "key1", "key2", "key3")
// client.Watch(fn, "key")
func Watch(fn func(tx *redis.Tx) error, keys ...string) {
	err := rdb.Watch(fn, keys...)
	if err != nil {
		panic(err)
	}
}

 类似资料: