首页 > 数据库 >golang使用redis锁(避免误解锁/死锁/过期引起并发):go-redis, redigo

golang使用redis锁(避免误解锁/死锁/过期引起并发):go-redis, redigo

时间:2024-03-21 18:11:35浏览次数:24  
标签:string val res redis golang 死锁 client key

【go-redis】简单实现方式,不会死锁/误解锁

package main

import (
    "context"
    "fmt"
    "sync"
    "time"

    redis2 "github.com/redis/go-redis/v9"
)

var mutex sync.Mutex

// redis加锁 sec:锁定秒数(避免死锁),value 锁唯一值(避免误解锁)
// import redis2 "github.com/redis/go-redis/v9"
// import "context"
func LockGoRedis(key string, val string, sec int) bool {
    mutex.Lock()
    defer mutex.Unlock()
    client := redis2.NewClient(&redis2.Options{
        Addr:     "127.0.0.1",
        Password: "",
        DB:       0,
    })
    ctx := context.Background()
    res, err := client.SetNX(ctx, key, val, time.Second*time.Duration(sec)).Result()
    if err != nil {
        fmt.Print("Lock error;", err.Error())
    }
    return res
}

// redis解锁 key,value一致才可解锁
func UnlockGoRedis(key string, val string) {
    client := redis2.NewClient(&redis2.Options{
        Addr:     "127.0.0.1",
        Password: "",
        DB:       0,
    })
    ctx := context.Background()
    if res, _ := client.Get(ctx, key).Result(); res == val {
        client.Del(ctx, key)
    }
}

缺点:不能自动展期,当业务处理时间超过锁定时长时,会被其他业务或客户端拿到锁,造成并发。
加个自动续期

func LockGoRedis(key string, val string, sec int, autoDelay bool) bool {
    mutex.Lock()
    defer mutex.Unlock()
    client := redis2.NewClient(&redis2.Options{
        Addr:     "127.0.0.1",
        Password: "",
        DB:       0,
    })
    ctx := context.Background()
    ttl := time.Second * time.Duration(sec)
    res, err := client.SetNX(ctx, key, val, ttl).Result()
    if err != nil {
        fmt.Print("Lock error;", err.Error())
    } else if autoDelay {
        // 锁自动续期
        go func() {
            for {
                time.Sleep(ttl / 2) //时间过半时再续期
                if res, _ := client.Get(ctx, key).Result(); res == val {
                    client.Expire(ctx, key, ttl)
                } else {
                    break // value不一致停止续期
                }
            }
        }()
    }
    return res
}

 

 

【redigo】版

// 加锁 sec:锁定秒数(避免死锁),value 锁唯一值(避免误解锁)
// import "github.com/gomodule/redigo/redis"
func LockRedigo(key string, val string, sec int, autoDelay bool) bool {
    mutex.Lock()
    defer mutex.Unlock()
    var pool = &redis.Pool{
        MaxIdle:     10,  //初始连接数量
        MaxActive:   0,   //连接池最大连接数量,(0自动设置)
        IdleTimeout: 300, //连接空闲时间 300秒
        Dial: func() (redis.Conn, error) {
            return redis.Dial("tcp", "127.0.0.1")
        },
    }
    client := pool.Get()

    ttl := time.Second * time.Duration(sec)
    reply, err := client.Do("setnx", key, val)
    if err != nil {
        fmt.Print("Lock error;", err)
        return false
    }
    if reply.(int64) == 1 {
        client.Do("expire", key, ttl.Seconds())
    }
    if autoDelay {
        // 锁自动续期
        go func() {
            for {
                time.Sleep(ttl / 2) //时间过半时再续期
                if res, _ := client.Do("get", key); res == val {
                    client.Do("expire", key, ttl.Seconds())
                } else {
                    break // value不一致停止续期
                }
            }
        }()
    }
    return true
}

// 解锁 key,value一致才可解锁
func UnlockRedigo(key string, val string) {
    var pool = &redis.Pool{
        MaxIdle:     10,  //初始连接数量
        MaxActive:   0,   //连接池最大连接数量,(0自动设置)
        IdleTimeout: 300, //连接空闲时间 300秒
        Dial: func() (redis.Conn, error) {
            return redis.Dial("tcp", "127.0.0.1")
        },
    }
    client := pool.Get()
    if res, _ := redis.String(client.Do("get", key)); res == val {
        client.Do("del", key)
    }
}

 

标签:string,val,res,redis,golang,死锁,client,key
From: https://www.cnblogs.com/yylyhl/p/18072942

相关文章

  • 分布式锁中的王者方案 - Redission
    文章目录5.1分布式锁-redission功能介绍5.2分布式锁-Redission快速入门5.3分布式锁-redission可重入锁原理5.4分布式锁-redission锁重试和WatchDog机制5.5分布式锁-redission锁的MutiLock原理5.1分布式锁-redission功能介绍基于setnx实现的分布式锁存在......
  • 解决SpringBoot环境下Redis哨兵模式连接失败问题,“NOAUTH Authentication required”
    io.lettuce.core.RedisCommandExceptionException:“NOAUTHAuthenticationrequired”在某行工作,项目上线代码,uat环境无异常,上到pp环境有问题,报redis连接不上;观察配置,发觉是apollo的配置是哨兵模式,有个哨兵密码。spring2.2.6RELEASE版本问题。于是写了全局配置,读取配置中......
  • 询问ChatGPT4,改造TodoList:把本地存储的localStorage修改成PHP+Redis
    这里照搬的是:免费极简设计网页版Todo  https://www.ricocc.com/todo/非常感谢原作者Rico。我很喜欢这个设计和风格,但是可惜只能本地存储,我又不想使用微软的TODO,登录倒无所谓,但是数据同步问题很大,实在头痛,所以放弃。我是菜鸟,只是刚好前段时间安装了Apache、PHP的一键安装包和......
  • Redisson-RTopic
    RTpoic简介:RTpoic是Redisson提供的用于实现发布-订阅(Pub/Sub)模式的类,它封装了 Redis 的发布和订阅功能,让开发者能够轻松地在分布式环境中进行消息的发布和订阅。实际上类似于Kafka、RocketMQ等一系列MessageQueue的生产-消费关系。自产自销:简单的说,可以实现一个服务中,自己......
  • 微软的Garnet的安装学习以及与Redis的简单对比
    微软的Garnet的安装学习以及与Redis的简单对比安装方式官网上面其实没有写如何安装garnet的很多人见识用nuget的方式进行安装我这边简单尝试了下也没看出来怎么用exe没办法只能学习dockerfile里面的内容在windows上面进行编译.下载地址https://codeload.github.com......
  • net core Web API 使用 Redis
    1.新建WebAPIapi2.新建类库Service安装StackExchange.Redis2.1Service中新建Redis文件夹,并创建接口IRedisService和类RedisSerivce点击查看代码publicinterfaceIRedisService{//获取Redis缓存值stringGetValue(stringkey);//获取值,并序列化TE......
  • 超高并发下,Redis热点数据风险破解
    ★Redis24篇集合1介绍作者是互联网一线研发负责人,所在业务也是业内核心流量来源,经常参与业务预定、积分竞拍、商品秒杀等工作。近期参与多场新员工的面试工作,经常就『超高并发场景下热点数据』可用性保障与候选人进行讨论。本文聚焦一些关键点技术进行讨论,并总结一些热......
  • golang 中 channel cap设为1原理 | 有无缓冲的channel
    在golang中,如果涉及消息传递或者是并发控制等,我们常常用到channel,channel的具体原理这里不讨论,今天主要看看有无缓冲以及缓冲值的设计。无缓冲的channel联系channel的数据结构mchan可知,就没得buf,但sendqrecvq这些肯定都是有的,所以在无缓冲的channel中,如果写者写入ch......
  • golang 多返回值的实现原理-转载
    之前一次面试时,面试官问到你知道golang的多返回值的实现吗,一脸懵逼,平时主要注重项目应用开发,对这块确实没关注,答得不好,各位大佬,以后建议也加强下基础哦。今天看看golang中多返回值的实现。可以简单认为c中多返回值的实现,其实就是通过寄存器将返回参数以指针形式传入传入参......
  • golang vs python 应用项目语言选择
    目录1.语言选择2.python语言特点及应用场景2.1语言特点1.简单2.易于学习3.自由且开放4.丰富的库5.互动模式6.跨平台性7.可扩展8.数据库9.可嵌入10.高级语言2.2应用场景Python在系统编程中的应用Python在网络爬虫方面的应用Python在人工智能、科学计算中的应用Python在WEB开发中......