go redis锁

redis经常用作分布式锁,这里记录一个简单的锁代码如下:

package main

import (
    "crypto/rand"
    "encoding/base64"
    "fmt"
    "github.com/go-redis/redis"
    "io"
    "sync"
    "time"
)

func main() {
    addr := "192.168.100.30:6379"
    rdb := redis.NewUniversalClient(&redis.UniversalOptions{
        Addrs:    []string {addr},
        Password: "", // no password set
        DB:       0,  // use default DB
    })
    defer func() {
        _ = rdb.Close()
    }()

    key := "gavin-lock"
    uid, err := Lock(rdb, key, time.Second*1, time.Second*2)
    if err == nil {
        _ = Unlock(rdb, key, uid)
    }
}

var randMutex sync.Mutex
var randBytes []byte

// 获取随机字串
func randToken() string {
    randMutex.Lock()
    defer randMutex.Unlock()

    if len(randBytes) == 0 {
        randBytes = make([]byte, 16)
    }

    if _, err := io.ReadFull(rand.Reader, randBytes); err != nil {
        return ""
    }
    return base64.RawURLEncoding.EncodeToString(randBytes)
}

func Lock(redisClient redis.UniversalClient, lockKey string, acquireTimeOut, lockTimeOut time.Duration) (token string, err error) {
    token = randToken()
    var acquireDuration = acquireTimeOut

    for acquireDuration > 0 {
        ok, err := redisClient.SetNX(lockKey, token, lockTimeOut).Result()
        if err != nil {
            fmt.Printf("redis锁 - 加锁失败 key: %s, token: %s, ttl: %v, err: %v\r\n", lockKey, token, lockTimeOut, err)
            return "", err
        }

        if ok {
            fmt.Printf("redis锁 - 加锁成功 key: %s, token: %s, ttl: %v\r\n", lockKey, token, lockTimeOut)
            return token, nil
        }
        time.Sleep(time.Millisecond * 100) // next: sleep 500ms
        acquireDuration -= time.Millisecond * 100
    }
    fmt.Printf("redis锁 - 加锁超时 key: %s, token: %s, ttl: %v\r\n", lockKey, token, acquireTimeOut)
    return "", fmt.Errorf("获取redis锁超时: %v\r\n", acquireTimeOut)
}

func Unlock(redisClient redis.UniversalClient, lockKey, token string) error {
    const script = if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end
    ret, err := redisClient.Eval(script, []string{lockKey}, token).Result()
    if err != nil {
        fmt.Printf("redis锁 - 解锁失败 key: %s, token: %s,  err: %v\r\n", lockKey, token, err)
        return err
    }

    if v, ok := ret.(int64); ok && v == 1 {
        fmt.Printf("redis锁 - 解锁成功 key: %s, token: %s\r\n", lockKey, token)
        return nil
    }

    fmt.Printf("redis锁 - 解锁失败 key: %s, token: %s, key已经过期\r\n", lockKey, token)
    return nil
}

windows技术爱好者

Original: https://www.cnblogs.com/majiang/p/15621088.html
Author: dz45693
Title: go redis锁

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/528886/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 软件基础的理论(1)

    软件基础的理论 一, 什么是软件产品 它是一个逻辑产品,没有实体,包括程序,文档和数据,需要通过终端设备才能体现出来功能和作用 二, 软件产品的中间过程文档 客户需求 &#…

    Linux 2023年6月7日
    091
  • Wine 运行百度云盘 中文乱码解决;wine中文乱码解决;fedora 34 运行百度网盘;

    今天需要下个 imagenet 的 ILSVRC2012 数据集,找到了网友在百度网盘中分享的下载好的; 但是因为本人使用的是 fedora 34 系统,所以尝试下载 百度网盘 l…

    Linux 2023年6月14日
    0108
  • AOP实现系统告警

    工作群里的消息怕过于安静,又怕过于频繁 一、业务背景 在开发的过程中会遇到各种各样的开发问题,服务器宕机、网络抖动、代码本身的bug等等。针对代码的bug,我们可以提前预支,通过发…

    Linux 2023年6月13日
    098
  • Python 获取字典中的第一个键

    提供两种方法: 使用 list 将字典的 key 转换成列表,然后取第一个元素 [0]。如果想要最后一个 key 的话,就取最后一个元素 [-1]。 >>> my…

    Linux 2023年6月7日
    081
  • 【Linux】socket通信编程

    socket通信 * – socket简介 – socket操作API函数 – 代码实现 socket简介 网络层的”ip地址&#8…

    Linux 2023年6月13日
    097
  • Makefile

    target … : prerequisites … command … … target可以是一个object file(目标文件),也可以是一个执行文件,还可以…

    Linux 2023年6月7日
    099
  • redis中setbit的用法

    原文地址:http://www.zhihu.com/question/27672245 在redis中,存储的字符串都是以二级制的进行存在的。举例:设置一个 key-value ,…

    Linux 2023年5月28日
    096
  • stat命令的实现

    任务详情 学习使用stat(1),并用C语言实现 提交学习stat(1)的截图 man -k ,grep -r的使用 伪代码 产品代码 mystate.c,提交码云链接 测试代码,…

    Linux 2023年5月27日
    0100
  • SpringBoot-Redis

    SpringBoot 整合 Redis SpringBoot-Redis 15.1 导入相关依赖 org.springframework.boot spring-boot-star…

    Linux 2023年6月14日
    096
  • 剑指offer计划21( 位运算简单)—java

    1.1、题目1 剑指 Offer 15. 二进制中1的个数 1.2、解法 通过判断每一位的与来识别1的数量。 1.3、代码 public class Solution { // y…

    Linux 2023年6月11日
    0141
  • ES查询区分大小写

    ES查询在默认的情况下是不区分大小写的,在5.0版本之后将 string类型拆分成两种新的数据类型, text用于全文搜索(模糊搜索), keyword用于关键字搜索(精确搜索)。…

    Linux 2023年6月8日
    0111
  • 源码安装apache脚本部署

    源码安装apache脚本部署 [root@localhost ~]# ls anaconda-ks.cfg httpd.tar.xz [root@localhost ~]# tar…

    Linux 2023年6月6日
    0110
  • Apache Bench压力测试使用方法

    Apache Bench是Apache轻量级压力测试工具,使用方便,简单,本文章简单介绍Windows平台使用Apache bench进行接口压力测试(ab测试) ApacheBe…

    Linux 2023年6月8日
    0103
  • CentOS shell中的变量

    shell中的变量 变量的介绍 变量即变化的量,核心是”变”与”量”二字,变即变化,量即衡量状态。 量:是记录现实世界当中的某种状态…

    Linux 2023年6月7日
    096
  • python 多线程

    python 多线程 多线程流程 导入模块 import threading 通过线程类型创建线程对象 线程对&a…

    Linux 2023年6月13日
    081
  • 刨析一下C++构造析构函数能不能声明为虚函数的背后机理?

    先说结论: 构造函数不能声…

    Linux 2023年6月6日
    0102
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球