zoukankan      html  css  js  c++  java
  • Redis分布式锁的实现以及工具类

    一、应用场景:

      本文应用的场景为在查询数据时,发现数据不存在此时就需要去查询数据库并且更新缓存,此时可能存在高并发的请求同时打在数据库上,而针对这种情况必须要给这些请求加锁,故而采用了分布式锁的方式。(当然分布式锁的应用场景较多,我只是针对本人工作的业务场景做了对应的处理)

    二、Redis锁的工具类:

    /**
     * Redis分布式锁
     */
    @Component
    public class RedisLock {
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        /**
         * 加锁
         * @param key
         * @param value 当前时间+超时时间
         * @return
         */
        public boolean lock(String key, String value) {
        
            if(redisTemplate.opsForValue().setIfAbsent(key, value)) {//相当于SETNX,setIfAbsent方法设置了为true,没有设置为false
                return true;
            }
            //假设currentValue=A   接下来并发进来的两个线程的value都是B  其中一个线程拿到锁,除非从始至终所有都是在并发(实际上这中情况是不存在的),只要开始时有数据有先后顺序,则分布式锁就不会出现“多卖”的现象
            String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
            //如果锁过期  解决死锁
            if (!StringUtils.isEmpty(currentValue)
                    && Long.parseLong(currentValue) < System.currentTimeMillis()) {
                //获取上一个锁的时间,锁过期后,GETSET将原来的锁替换成新锁
                String oldValue = String.valueOf(redisTemplate.opsForValue().getAndSet(key, value));
                if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
                    return true;
                }
            }
    
            return false;//拿到锁的就有执行权力,拿不到的只有重新再来,重新再来只得是让用户手动继续抢单
        }
    
        /**
         * 解锁
         * @param key
         * @param value
         */
        public void unlock(String key, String value) {
            try {
                String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
                if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                    redisTemplate.opsForValue().getOperations().delete(key);
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

    三、业务代码:

    JSONArray allApplyForms = null;
    if (this.redisActivityService.exists(RedisKeys.ApplyFormList_KEY+String.valueOf(activityId))) {
      // 如果redis缓存在有该活动的作品列表,则直接从redis中获取 Object allApplyFormsJSON = this.redisActivityService.get(RedisKeys.ApplyFormList_KEY+String.valueOf(activityId)); allApplyForms = JSONArray.fromObject(allApplyFormsJSON.toString());
    }
    else { long time = System.currentTimeMillis()+(20 * 1000); if(!redisLock.lock("ApplyFormListLock", String.valueOf(time))){ return CORSUtil.getResult(0, "当前访问量大,刷新一下", null, callback); } allApplyForms = this.activityService.getAllApplyForms(activityId, thumbnailWidth,thumbnailHeight, contentCode, formTitle, flag,formModel); if(allApplyForms ==null){ return CORSUtil.getResult(0, "没有对应的参选表单", null,callback); } this.redisActivityService.set(RedisKeys.ApplyFormList_KEY+String.valueOf(activityId), allApplyForms.toString(),Long.parseLong(systemConfigService.getConfig("redisOverTime"))+new Random().nextInt(200)); redisLock.unlock("ApplyFormListLock", String.valueOf(time)); }

    1,从redis中获取对应的数据,如果获取到直接返回,如果没有就走接下来的加锁代码

    2,如果加锁不成功,则说明已经有请求进入到后面的业务逻辑,这时候就直接返回给客户端,等待

    3,如果加锁成功,则查询数据并更新Redis,最后再释放锁

  • 相关阅读:
    服务方式加载卸载NT驱动函数集
    《Windows核心编程》学习笔记(12)– 虚拟内存
    《Windows核心编程》学习笔记(14)– 堆
    数据库连接错误:提示TCP端口1433,sql server 2008 Connection refused:connect
    Windows驱动开发技术详解笔记
    Struts2文件上传的大小限制问题
    pragma comment的使用 pragma预处理指令详解
    解决FastCGI Error Error Number: 2147467259 (0x80004005). 和 Error Number: 1073741819 (0xc0000005).
    PHP中的日期处理
    mysql远程连接10061错误
  • 原文地址:https://www.cnblogs.com/bbgs-xc/p/11326468.html
Copyright © 2011-2022 走看看