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,最后再释放锁

原文地址:https://www.cnblogs.com/bbgs-xc/p/11326468.html

时间: 2024-10-07 18:01:07

Redis分布式锁的实现以及工具类的相关文章

redis分布式锁小试

一.场景 项目A监听mq中的其他项目的部署消息(包括push_seq, status, environment,timestamp等),然后将部署消息同步到数据库中(项目X在对应环境[environment]上部署的push_seq[项目X的版本]).那么问题来了,mq中加入包含了两个部署消息 dm1 和 dm2,dm2的push_seq > dm1的push_seq,在分布式的情况下,dm1 和 dm2可能会分别被消费(也就是并行),那么在同步数据库的时候可能会发生 dm1 的数据保存 后于

基于redis分布式锁实现“秒杀”

最近在项目中遇到了类似"秒杀"的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓"秒杀"的基本思路. 业务场景 所谓秒杀,从业务角度看,是短时间内多个用户"争抢"资源,这里的资源在大部分秒杀场景里是商品:将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确. 一些可能的实现 刚才提到过,实现秒杀的关键点是控制线程对资源的争抢,根据基本的线程知识,可

SpringBoot集成Redis分布式锁以及Redis缓存

https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 <!-- 引入redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifa

Redis分布式锁实现简单秒杀功能

这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题. 主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了.这样就处理了多线程并发问题的同时也保证了服务器的性能的稳定. 接下来我们使用redis的分布式锁来进行枷锁处理: 我们可以在进入下单的方法后将核心的方法加锁,然后离开后进行解锁 主要三步: 加锁 核心方法 解锁 首页分布式加锁解锁工具类: @Component public class RedisLock { private static

Redis分布式锁解决抢购问题

首先分享一个业务场景-抢购.一个典型的高并发问题,所需的最关键字段就是库存,在高并发的情况下每次都去数据库查询显然是不合适的,因此把库存信息存入Redis中,利用redis的锁机制来控制并发访问,是一个不错的解决方案. 首先是一段业务代码: @Transactional public void orderProductMockDiffUser(String productId){ //1.查库存 int stockNum = stock.get(productId); if(stocknum =

Redlock:Redis分布式锁最牛逼的实现

普通实现 说道Redis分布式锁大部分人都会想到:setnx+lua,或者知道set key value px milliseconds nx.后一种方式的核心实现命令如下: - 获取锁(unique_value可以是UUID等) SET resource_name unique_value NX PX 30000 - 释放锁(lua脚本中,一定要比较value,防止误解锁) if redis.call("get",KEYS[1]) == ARGV[1] then return red

死磕 java同步系列之redis分布式锁进化史

问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 本章我们将介绍如何基于redis实现分布式锁,并把其实现的进化史从头到尾讲明白,以便大家在面试的时候能讲清楚

收藏慢慢看系列:简洁实用的Redis分布式锁用法

在微服务中很多情况下需要使用到分布式锁功能,而目前比较常见的方案是通过Redis来实现分布式锁,网上关于分布式锁的实现方式有很多,早期主要是基于Redisson等客户端,但在Spring Boot2.x以上版本中使用Redis时,其客户端库已经默认使用lettuce.所以本文将直接介绍在Spring Boot2.x以上项目中快速使用Redis分布式锁的功能的方法,希望能够更新你的知识库! Redis分布式锁原理概述 实际上Redis服务本身并不提供分布式锁这样的机制,但是作为全局Key-Valu

redis分布式锁解决超卖问题

1.1 redis事物 1.redis事物介绍 1. redis事物是可以一次执行多个命令,本质是一组命令的集合. 2. 一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入 作用:一个队列中,一次性.顺序性.排他性的执行一系列命令 2.multi 指令基本使用 1. 下面指令演示了一个完整的事物过程,所有指令在exec前不执行,而是缓存在服务器的一个事物队列中 2. 服务器一旦收到exec指令才开始执行事物队列,执行完毕后一次性返回所有结果 3. 因为redis是单线程的,所