permalink | sidebarBasedOnContent |
---|---|
/ |
true |
go 社区有很多 redis 库, 但是大多数库在 redis 返回 nil 时候用 error 表示.例如使用GET方法:
cmd := client.Get(ctx, "name")
err = cmd.Err()
isNil := false
if err != nil {
if errors.Is(err, redis.Nil) {
isNil = true
} else {
return err
}
}
if isNil {
// do some
} else {
log.Print(cmd.String())
}
代码写的复杂,心很累.
goclub/redis 的接口风格是
value, isNil, err := red.GET{Key:key}.Do(ctx, client) ; if err != nil {
return
}
if isNil {
// do some
} else {
log.Print(value)
}
redis 的核心是 RESP 协议. goclub/redis 提供以下接口对应 RESP.
// Connecter RESP
type Connecter interface {
DoStringReply(ctx context.Context, args []string) (reply string, isNil bool, err error)
DoStringReplyWithoutNil(ctx context.Context, args []string) (reply string, err error)
DoIntegerReply(ctx context.Context, args []string) (reply int64, isNil bool, err error)
DoIntegerReplyWithoutNil(ctx context.Context, args []string) (reply int64, err error)
DoArrayIntegerReply(ctx context.Context, args []string) (reply []OptionInt64, err error)
DoArrayStringReply(ctx context.Context, args []string) (reply []OptionString, err error)
Eval(ctx context.Context, script Script) (reply Reply, isNil bool, err error)
EvalWithoutNil(ctx context.Context, script Script) (reply Reply, err error)
}
你可以自由的使用任何命令.
replyInt64, err = client.DoIntegerReplyWithoutNil(
ctx,
[]string{
"HSET", key, "name", "goclub", "age", "18",
})
if err != nil {
return
}
你也可以查看 red.API
查看 goclub/redis 对哪些方法进行了封装
像是 RESP Simple Strings
这类操作你可以根据 redis 是否会返回 nil 去调用 DoStringReply
或 DoStringReplyWithoutNil
脚本则使用 Eval
或者EvalWithoutNil
script := `
if redis.call("GET", KEYS[1]) == ARGV[1]
then
return redis.call("DEL", KEYS[1])
else
return 0
end
`
reply, err := client.EvalWithoutNil(ctx, Script{
KEYS: []string{key},
ARGV: []string{value},
Script: script,
}) ; if err != nil {
return
}
/*
你可以根据 script 内容调用一下 reply 方法
reply.Int64()
reply.Uint64()
reply.String()
reply.Int64Slice()
reply.StringSlice()
*/
你可以将 goclub/redis 理解为是一个驱动库,是一个"壳". goclub/redis 能通过接口适配 go 社区的说有 redis 库.
goclub/redis 还基于redis实现了了一些实用的方法,帮助开发人员提高开发效率.防止重复造轮子.
触发器
// Trigger 触发器
// 每5分钟出现3次则触发,但是10分钟内只触发一次
func exmaple () {
triggered, err := red.Trigger{
Namespace: "pay_fail_alarm",
Interval: time.Minute*5,
Threshold: 3,
Frequency: time.Minute*5,
}.Do(ctx, client) ; if err != nil {
return
}
if triggered {
// do some
}
}
互斥锁
mutex := red.Mutex{
Key: key,
// Expire 控制锁定时间
Expire: time.Millisecond*100,
// Retry 当锁被占用时进入循环重试(此时会堵塞)
// Retry.Times 重试上锁多少次
// Retry.Interval 重试上锁间隔
Retry: red.Retry{
Times: 3,
Interval:time.Millisecond*100,
},
}
lockSuccess, unlock, err := mutex.Lock(context.TODO(), client) ; if err != nil {
// 锁失败
return
}
if lockSuccess == false {
// 锁被占用
return
}
// 处理某些业务
err = unlock(context.TODO()) ; if err != nil {
*mutexCount--
// 解锁失败
log.Printf("%+v", err)
return
}
// 解锁成功
递增限制器
alarm_1 := IncrLimiter{
Namespace: "incr_limiter_alarm_1",
Expire: time.Second * 10,
Maximum: 3,
}
/* 第1次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
return
} // limited = false
/* 第2次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
return
} // limited = false
/* 第3次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
return
} // limited = false
/* 第4次 */
limited, err := alarm_1.Do(ctx, client) ; if err != nil {
return
} // limited = true
设值限制器
使用场景: 限制用户每天只能试读3个章节(如果不允许一天内反复试读相同章节则可以使用 IncrLimiter )
注意:
如果 Key = free_trial:{userID} Expire = 24h 是限制24小时
如果 Key = free_trial:2022-01-01:{userID} Expire = 24h 是限制每天
/* 第1次 用户1访问了章节1 */
limited, err := SetLimiter{
Key: "free_trial:2022-05-25:userID:1",
Member: "1"
Expire: time.Hour * 24,
Maximum: 3,
}.Do(ctx, client) ; if err != nil {
return
} // limited = false
/* 第2次 用户1重复访问了章节1 */
limited, err := SetLimiter{
Key: "free_trial:2022-05-25:userID:1",
Member: "1"
Expire: time.Hour * 24,
Maximum: 3,
}.Do(ctx, client) ; if err != nil {
return
} // limited = false
/* 第3次 用户1访问了章节2 */
limited, err := SetLimiter{
Key: "free_trial:2022-05-25:userID:1",
Member: "2"
Expire: time.Hour * 24,
Maximum: 3,
}.Do(ctx, client) ; if err != nil {
return
} // limited = false
/* 第4次 用户1访问了章节3 */
limited, err := SetLimiter{
Key: "free_trial:2022-05-25:userID:1",
Member: "3"
Expire: time.Hour * 24,
Maximum: 3,
}.Do(ctx, client) ; if err != nil {
return
} // limited = false
/* 第5次 用户1访问了章节4 */
limited, err := SetLimiter{
Key: "free_trial:2022-05-25:userID:1",
Member: "4"
Expire: time.Hour * 24,
Maximum: 3,
}.Do(ctx, client) ; if err != nil {
return
} // limited = true