简单分布式锁(基于redis)

简单分布式锁(基于redis),第1张

简单分布式锁(基于redis)

此方法主要理解 分布式锁工作原理:推荐使用
学习redisson 了解工作原理:
https://blog.csdn.net/qq_17040587/article/details/121516553
终极方案用springCache的例子
https://blog.csdn.net/qq_17040587/article/details/121522421

简单分布式锁(基于redis)

此文章限于理解分布式工作原理,实际开发推荐后续文章的the Redlock 设计.java对应的是Redisson.

核心:原子加锁 原子解锁

加锁相关redis语句:

set lock 1 NX  解释:lock键无占用才设置键lock值为1

set lock 1 EX 300 NX 解释:lock键无占用时才设置键lock值为1 有效时间为:300s

解锁相关语句:

if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end

思路过程代码:

    
    public Map>  getCatalogJsonFromDbWithRedisLock() {
        
        //1.占分布式锁 去redis占坑 【set lock 1 EX 30 NX】 lock键无占用时才设置键lock值为1 有效时间为:300s
        String uuid = UUID.randomUUID().toString();
        //设置300s的过期时间 放置执行业务过程中 锁过期了。 让过期时间靠谱的大约业务时间 后面再执行脚本解锁
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(RedisConstant.INDEX_CATALOGJSON_LOCK, uuid,300,TimeUnit.SECONDS);
        if(lock){
            System.out.println("获取分布式锁成功");
        //加锁成功 ...  执行业务
            Map> dataFromDb = null;
            try{
               dataFromDb = getDataFromDb();
            }finally {
                //保证删除的锁 是自己的锁再删除
                // 判断的原因:lock过期后,会有一个请求x可以进来,如果此时删锁,会导致x的占位失败会导致多个人进来
                //获取值锁 远程
                //String lockValue = stringRedisTemplate.opsForValue().get(RedisConstant.INDEX_CATALOGJSON_LOCK);
                //瞬时异常: lockValue去请求返回的路上过期    lockValue带回来的确实是自己存的内容,此时lock已经被人占用成功,也会误删别人的锁
                // if(uuid.equals(lockValue)){
                //解锁远程
                // stringRedisTemplate.delete(RedisConstant.INDEX_CATALOGJSON_LOCK); //删锁失败 造成思索
                // }
                // ↓ 优化
                //获取值锁 + 对比成功删除  合并原子 *** 作  脚本Lua脚本解锁
                String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                Long unlock = stringRedisTemplate.execute(new DefaultRedisscript(script, Long.class),
                        Arrays.asList(RedisConstant.INDEX_CATALOGJSON_LOCK), uuid);
            }
            return dataFromDb;
        }else{
            System.out.println("获取分布式锁失败 等待重试..");
            //加锁失败 ...重试 synchronized()
            //休眠100ms重试
            try {
                Thread.sleep(200);
            }catch ( Exception e){
            }
            return getCatalogJsonFromDbWithRedisLock();// 自旋方式
        }
    }

两个必要性原子 *** 作:

加锁 :设置锁独占 设置过期时间

解锁:查询锁值 删除所

整合:

    
    public Map>  getCatalogJsonFromDbWithRedisLock() {

        //1.占分布式锁 去redis占坑 【set lock 1 EX 30 NX】 lock键无占用时才设置键lock值为1 有效时间为:300s
        String uuid = UUID.randomUUID().toString();
        //设置300s的过期时间 放置执行业务过程中 锁过期了。 让过期时间靠谱的大约业务时间 后面再执行脚本解锁
        Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(RedisConstant.INDEX_CATALOGJSON_LOCK, uuid,300,TimeUnit.SECONDS);
        if(lock){
            System.out.println("获取分布式锁成功");
        //加锁成功 ...  执行业务
            Map> dataFromDb = null;
            try{
               dataFromDb = getDataFromDb();
            }finally {
                //获取值锁 + 对比成功删除  合并原子 *** 作  脚本Lua脚本解锁
                String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
                Long unlock = stringRedisTemplate.execute(new DefaultRedisscript(script, Long.class),
                        Arrays.asList(RedisConstant.INDEX_CATALOGJSON_LOCK), uuid);
            }
            return dataFromDb;
        }else{
            System.out.println("获取分布式锁失败 等待重试..");
            //加锁失败 ...重试 synchronized()
            //休眠100ms重试
            try {
                Thread.sleep(200);
            }catch ( Exception e){
            }
            return getCatalogJsonFromDbWithRedisLock();// 自旋方式
        }
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5597201.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存