
实现了一个基于 Redis 的分布式锁,包括加锁和解锁功能。加锁时生成一个随机的 requestId 作为锁的标识,并设置过期时间以防止死锁。解锁时通过事务确保只有加锁的客户端才能释放锁,保证了锁的安全性。
package redis_lock
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"math/rand"
"testing"
"time"
)
type RedisLock struct {
Client *redis.Client
}
func NewRedisLock() *RedisLock {
return &RedisLock{
Client: redis.NewClient(&redis.Options{
Addr: "localhost:6379", // Redis服务器地址
Password: "", // 密码,没有则留空
DB: 0, // 使用默认DB
}),
}
}
func TestRedisLock(t *testing.T) {
ctx := context.Background()
r := NewRedisLock()
lockKey := "mytTestKey"
requestId, err := r.Lock(ctx, lockKey, 600) //锁10分钟,保证任务执行完
if err != nil {
fmt.Println(err)
return
}
if requestId == "" {
return
}
defer r.UnLock(ctx, lockKey, requestId)
}
/*
1、加锁功能
1.1、锁名key:lockKey
1.2、随机生成的一个value: requestId
1.3、超时时间,上锁后超过此时间则自动释放锁:expire
*/
func (r *RedisLock) Lock(ctx context.Context, lockKey string, expire int64) (string, error) {
requestId := GenRand(6) //锁的标识
nx := r.Client.SetNX(ctx, lockKey, requestId, time.Duration(expire)*time.Second)
if nx.Val() {
return requestId, nil
}
return "", nx.Err()
}
/*
2、释放锁
2.1、锁名key:lockKey
2.2、释放锁的标识 requestId (谁加的锁释放对应的锁,不能将其他人的锁释放了,解铃还须系铃人)
*/
func (r *RedisLock) UnLock(ctx context.Context, key, requestId string) bool {
flag := false
//监视key,准备开始事务
_ = r.Client.Watch(ctx, func(tx *redis.Tx) error {
for {
v, _ := tx.Get(ctx, key).Result()
// 通过前面返回的v值判断是不是该锁,若是该锁,则删除,释放锁
if v == requestId {
_, err := tx.Del(ctx, key).Result()
if err != nil { //删除失败
continue
}
flag = true
}
break
}
tx.Unwatch(ctx, key)
return nil
}, key)
return flag
}
const (
ascstr = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
)
// 获取随机字符,输出字符数由参数size指定。
func GenRand(size int) string {
// 以时间作为初始化种子
rand.Seed(time.Now().UnixNano())
var bytes = make([]byte, size)
rand.Read(bytes)
length := byte(len(ascstr))
for k, v := range bytes {
bytes[k] = ascstr[v%length]
}
return string(bytes)
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。