redis分布式锁实现(golang版)
代码
.
.
.
const redisMutexLockExpTime = 15
// TryGetDistributedLock 分布式锁获取
// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一
func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool {
if isNegative { // 多次尝试获取
retry := 1
for {
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
// 获取锁成功
if err == nil && ok == "OK" {
return true
}
// 尝试多次没获取成功
if retry > 10 {
return false
}
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
retry += 1
}
} else { // 只尝试一次
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
// 获取锁成功
if err == nil && ok == "OK" {
return true
}
return false
}
}
// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型
func ReleaseDistributedLock(lockKey, requestId string) (bool, error) {
luaScript := `` # 因为页面显示有问题,这里多加了个反引号,注意去除
if redis.call("get",KEYS[1]) == ARGV[1]
then
return redis.call("del",KEYS[1])
else
return 0
end`` # 因为页面显示有问题,这里多加了个反引号,注意去除
do, err := cache.Do("eval", luaScript, 1, lockKey, requestId)
fmt.Println(reflect.TypeOf(do))
fmt.Println(do)
if utils.AnyToInt64(do) == 1 {
return true, err
} else {
return false, err
}
}
// HandleBalanceDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁
func HandleBalanceDistributedLock(paramA,paramB,requestIdPrefix string) (cb func(), err error){
lockKey := fmt.Sprintf("%s:xxx_lock:%s", paramA, paramB)
requestId := GetDistributedLockRequestId(requestIdPrefix)
lockOk := TryGetDistributedLock(lockKey, requestId, true)
if !balanceLockOk {
return nil, errors.New("系统繁忙,请稍后再试")
}
cb = func() {
_, _ = ReleaseDistributedLock(lockKey, requestId)
}
return cb, nil
}
使用示例
// 获取锁
cb, err := HandleBalanceDistributedLock(c.GetString("mid"), utils.IntToStr(user.Info.Uid), "acq_reward")
if err != nil {
return err
}
// 加锁成功则最后释放锁
if cb != nil {
defer cb()
}
参考
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: