使用golang语言实现了各种redis的实现
包括初始化redisDb,在服务重启时需要删除的 redis 缓存,对redis里的值进行自增操作并设置过期时间,简单分布式锁,set,get,ttl,delete等等。
哎嘿,你就看吧,一看一个不吱声。
func InitRedisDB(cfg *dbridgeredis.RedisConfig) {defer ClearCacheOnServiceRestart()client := dbridgeredis.InitRedis(cfg)if cfg.ClusterEnable {RedisClusterDB = client.(*redis.ClusterClient)} else {redisDB = client.(*redis.Client)injectredis.SetRedis(redisDB)injectredis.Inject()}
}// IncrAndExpire 对redis里的值进行自增操作并设置过期时间
func IncrAndExpire(key string, expiration time.Duration) (count int64) {c := context.Background()currentValues := redisDB.Get(c, key)logger.Info(fmt.Sprintf("redis key=%s, currentValues=%v", key, currentValues))result := redisDB.Incr(c, key)if err := result.Err(); err != nil {logger.Error("incr redis key failed", err)} else {count = result.Val()if err := redisDB.Expire(c, key, expiration).Err(); err != nil {logger.Error("set redis key expire failed", err)}}return
}// Set value需要传指针地址
func Set(key string, value interface{}, expiration time.Duration) error {c := context.Background()if key == "" || value == nil {return errors.New("param empty")}err := hystrixPing()if err != nil {return err}data, err := json.Marshal(value)if err != nil {return err}err = redisDB.Set(c, key, data, expiration).Err()return err
}func SetNX(key string, value interface{}, expiration time.Duration) error {c := context.Background()if key == "" || value == nil {return errors.New("param empty")}data, err := json.Marshal(value)if err != nil {return err}return redisDB.SetNX(c, key, data, expiration).Err()
}// SetNXForLock 简单分布式锁
func SetNXForLock(key string, expiration time.Duration) error {c := context.Background()if key == "" {return errors.New("key empty")}suc := redisDB.SetNX(c, key, 1, expiration)if suc.Val() {return nil}return errors.New(locales.TM("common.key_exist", nil))
}// RedisDistributedLock 方便的在定时任务中使用
func RedisDistributedLock(key string, expiration time.Duration, execFunction func()) (err error) {// 设置Redis中的键为分布式锁,如果不存在if err = SetNXForLock(key, expiration); err != nil {return fmt.Errorf(fmt.Sprintf("Set redis distributed lock error|key=%s|err=", key), err)}defer func() {if err := recover(); err != nil {logger.Error(fmt.Sprintf("exec function panic: %v", err), nil)}// 删除Redis中的键err = Delete(key)if err != nil {logger.Error(fmt.Sprintf("Delete redis distributed lock error|key=%s|err=", key), err)}}()execFunction()return
}// Get ret需要传指针地址
func Get(key string, ret interface{}) error {c := context.Background()if key == "" {return errors.New("param empty")}err := hystrixPing()if err != nil {return err}handle := redisDB.Get(c, key)if err := handle.Err(); err != nil {return err}res := handle.Val()return json.Unmarshal([]byte(res), &ret)
}func TTL(key string) (int64, error) {c := context.Background()if key == "" {return -1, errors.New("param empty")}err := hystrixPing()if err != nil {return -1, err}handle := redisDB.TTL(c, key)if err := handle.Err(); err != nil {return -1, err}return int64(handle.Val().Seconds()), nil
}// Delete 删除缓存
func Delete(key string) error {c := context.Background()if key == "" {return fmt.Errorf("empty key when delete")}err := hystrixPing()if err != nil {return err}return redisDB.Del(c, key).Err()
}func Expire(key string, expiration time.Duration) error {return redisDB.Expire(context.Background(), key, expiration).Err()
}func Scan(cursor uint64, match string, count int64) *redis.ScanCmd {return redisDB.Scan(context.Background(), cursor, match, count)
}func FlushAll() {redisDB.FlushDB(context.Background())
}// Keys 获取指定 key 的所有值,并以切片的形式返回
func Keys(key string) []string {c := context.Background()var ret []stringerr := hystrixPing()if err != nil {return ret}if key == "" {return ret}handle := redisDB.Keys(c, key)if err := handle.Err(); err != nil {logger.Error("Keys err", err)return ret}res := handle.Val()return res
}// ZAdd 给有序集合中添加元素及分数
func ZAdd(key string, member interface{}, score float64) (int64, error) {c := context.Background()item := &redis.Z{Score: score,Member: member,}addedCount, err := redisDB.ZAdd(c, key, item).Result()if err != nil {logger.Error("redis add member to zadd error", err)return 0, err}return addedCount, nil
}// ZRemRangeByRank 移除有序集合中给定的排名区间内的所有成员
// Redis ZREMRANGEBYRANK 移除有序集key中,指定排名(rank)区间 start 和 stop 内的所有成员。下标参数start和stop都是从0开始计数,
// 0是分数最小的那个元素。索引也可是负数,表示位移从最高分处开始数。例如,-1是分数最高的元素,-2是分数第二高的,依次类推。
func ZRemRangeByRank(key string, start, stop int64) (int64, error) {c := context.Background()removeCount, err := redisDB.ZRemRangeByRank(c, key, start, stop).Result()if err != nil {logger.Error("redis remove zadd member error", err)return 0, err}return removeCount, nil
}// ZRange 获取有序集合中的元素,并对其按照分数进行从大到小排序
func ZRange(key string, start, stop int64) (members []string, err error) {c := context.Background()members, err = redisDB.ZRange(c, key, start, stop).Result()if err != nil {logger.Error("redis get zadd error", err)return nil, err}if len(members) > 1 {members = utils.ReverseSlice(members)}return
}func SAdd(key string, value interface{}) (int64, error) {c := context.Background()addedCount, err := redisDB.SAdd(c, key, value).Result()if err != nil {logger.Error("redis setting error", err)return 0, err}return addedCount, nil
}func SIsMember(key string, value int) (bool, error) {c := context.Background()existValue, err := redisDB.SIsMember(c, key, value).Result()if err != nil {logger.Error("查询失败", err)return false, err}return existValue, nil
}func SIsMemberString(key string, value string) (bool, error) {c := context.Background()existValue, err := redisDB.SIsMember(c, key, value).Result()if err != nil {logger.Error("查询失败", err)return false, err}return existValue, nil
}// Incr 对redis里的值进行自增操作
func Incr(key string) (int, error) {err := hystrixPing()if err != nil {return 0, err}c := context.Background()cmd := redisDB.Incr(c, key)return int(cmd.Val()), cmd.Err()
}// Decr 对redis里的值进行自减操作
func Decr(key string) (int, error) {c := context.Background()cmd := redisDB.Decr(c, key)return int(cmd.Val()), cmd.Err()
}// DeleteBatch 批量删除缓存
func DeleteBatch(key []string) error {err := hystrixPing()if err != nil {return err}c := context.Background()return redisDB.Del(c, key...).Err()
}func UnlinkPrefixKeys(prefix string) error {err := hystrixPing()if err != nil {return err}c := context.Background()keys, _ := redisDB.Keys(c, prefix).Result()if len(keys) > 0 {// unlink 异步删err = UnlinkKeys(keys)if err != nil {logger.Error("redis unlink keys error", err)}}return nil
}func UnlinkKeys(keys []string) error {err := hystrixPing()if err != nil {return err}c := context.Background()return redisDB.Unlink(c, keys...).Err()
}func HMget(key string, fields []string) (val []interface{}, err error) {c := context.Background()return redisDB.HMGet(c, key, fields...).Result()
}func HSet(key string, field, value interface{}) (res int64, err error) {c := context.Background()return redisDB.HSet(c, key, field, value).Result()
}func HGet(key string, field string) (res string, err error) {c := context.Background()return redisDB.HGet(c, key, field).Result()
}func HDel(key, field string) (res int64, err error) {c := context.Background()return redisDB.HDel(c, key, field).Result()
}func HGetAll(key string) (map[string]string, error) {c := context.Background()return redisDB.HGetAll(c, key).Result()
}func HMSet(key string, fields map[string]string) (bool, error) {c := context.Background()return redisDB.HMSet(c, key, fields).Result()
}func Lock(lockKey string, expiration time.Duration) (bool, error) {var resp *redis.BoolCmdfor {goId := utils.GetCurrentGoroutineId()resp = redisDB.SetNX(context.Background(), lockKey, goId, expiration) //返回执行结果lockSuccess, err := resp.Result()if err == nil && lockSuccess {//抢锁成功,开启看门狗 并跳出,否则失败继续自旋tls.GoSafe(tls.GetLangLocalStorage(), func() { watchDog(goId, lockKey, expiration) })return lockSuccess, err}//time.Sleep(time.Millisecond * 30) //可以适当休眠return lockSuccess, err}
}// 自动续期看门狗
func watchDog(goId int, lockKey string, expiration time.Duration) {// 创建一个定时器NewTicker, 每隔2秒触发一次,类似于闹钟expTicker := time.NewTicker(time.Second * 2)//确认锁与锁续期打包原子化script := redis.NewScript(`if redis.call('get', KEYS[1]) == ARGV[1]thenreturn redis.call('expire', KEYS[1], ARGV[2])elsereturn 0end`)for {select {case <-expTicker.C: //因为上边是用NewTicker创建的定时器,所以每隔2s都会触发resp := script.Run(context.Background(), redisDB, []string{lockKey}, goId, expiration)if result, err := resp.Result(); err != nil || result == int64(0) {//续期失败_, _ = fmt.Printf("expire lock failed:%s", err)}case <-unlockCh: //任务完成后用户解锁通知看门狗退出return}}
}func Unlock(lockKey string) error {script := redis.NewScript(`if redis.call('get', KEYS[1]) == ARGV[1]thenreturn redis.call('del', KEYS[1])elsereturn 0end`)resp := script.Run(context.Background(), redisDB, []string{lockKey}, utils.GetCurrentGoroutineId())if result, err := resp.Result(); err != nil || result == 0 {return fmt.Errorf(fmt.Sprintf("unlock %s failed: %s", lockKey, err))}//删锁成功后,通知看门狗退出unlockCh <- struct{}{}return nil
}// LRange LRange
func LRange(key string, start, stop int64) (members []string, err error) {c := context.Background()members, err = redisDB.LRange(c, key, start, stop).Result()if err != nil {logger.Error("redis get LRange error", err)return nil, err}return
}// RPop RPop
func RPop(key string) (err error) {c := context.Background()err = redisDB.RPop(c, key).Err()if err != nil {logger.Error("redis RPop error", err)return err}return
}// LPush LPush
func LPush(key string, values ...interface{}) (err error) {c := context.Background()err = redisDB.LPush(c, key, values).Err()if err != nil {logger.Error("redis LPush error", err)return err}return
}func LPushValue(key string, value interface{}) error {c := context.Background()if key == "" || value == nil {return errors.New("param empty")}data, err := json.Marshal(value)if err != nil {return err}return redisDB.LPush(c, key, data).Err()
}func RPopValue(key string, ret interface{}) error {c := context.Background()if key == "" {return errors.New("param empty")}handle := redisDB.RPop(c, key)if err := handle.Err(); err != nil {return err}res := handle.Val()return json.Unmarshal([]byte(res), &ret)
}func AddUniqueLock() (err error) {pc, _, _, ok := runtime.Caller(1)if !ok {logger.Info("AddUniqueLock err")return}funcName := runtime.FuncForPC(pc).Name()err = SetNXForLock(fmt.Sprintf("crond_lock:%s", funcName), 3*time.Second)return
}func AddUniqueLockSecTime(sec int64) (err error) {pc, _, _, ok := runtime.Caller(1)if !ok {logger.Info("AddUniqueLock err")return}funcName := runtime.FuncForPC(pc).Name()err = SetNXForLock(fmt.Sprintf("crond_lock:%s", funcName), time.Duration(sec)*time.Second)return
}func Exists(key string) (int64, error) {c := context.Background()return redisDB.Exists(c, key).Result()
}
func SAddNX(key string, value interface{}, expiration time.Duration) (int64, error) {c := context.Background()addedCount, err := redisDB.SAdd(c, key, value).Result()if err != nil {logger.Error("redis setting error", err)return 0, err}redisDB.Expire(c, key, expiration)return addedCount, nil
}func BLPop(key string, timeout time.Duration) ([]string, error) {err := hystrixPing()if err != nil {return nil, err}return redisDB.BLPop(context.Background(), timeout, key).Result()
}func Watch(key string, function func(tx *redis.Tx) error) error {err := hystrixPing()if err != nil {return err}return redisDB.Watch(context.Background(), function, key)
}func RPush(key string, values ...interface{}) (err error) {err = hystrixPing()if err != nil {return err}return redisDB.RPush(context.Background(), key, values).Err()
}