首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >redis分布式锁-被其他人解锁

redis分布式锁-被其他人解锁

原创
作者头像
王宝
发布2024-11-28 10:18:44
发布2024-11-28 10:18:44
1840
举报

说明

实现了一个基于 Redis 的分布式锁,包括加锁和解锁功能。加锁时生成一个随机的 requestId 作为锁的标识,并设置过期时间以防止死锁。解锁时通过事务确保只有加锁的客户端才能释放锁,保证了锁的安全性。

示例

代码语言:txt
复制
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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 说明
  • 示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档