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

这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题。

主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了。这样就处理了多线程并发问题的同时也保证了服务器的性能的稳定。

接下来我们使用redis的分布式锁来进行枷锁处理:

我们可以在进入下单的方法后将核心的方法加锁,然后离开后进行解锁

主要三步:

加锁

核心方法

解锁

首页分布式加锁解锁工具类:

@Component
public class RedisLock {
    private static Logger logger = LoggerFactory.getLogger(RedisLock.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 加锁
     * @param key
     * @param value 当前事件+超时事件
     * @return
     */
    public boolean lock(String key,String value){
        //加锁成功
        if (redisTemplate.opsForValue().setIfAbsent(key,value)){
            return true;
        }
        //假如currentValue=A先占用了锁  其他两个线程的value都是B,保证其中一个线程拿到锁
        String currentValue = redisTemplate.opsForValue().get(key);
        //锁过期  防止出现死锁
        if (!StringUtils.isEmpty(currentValue) &&
                Long.parseLong(currentValue) < System.currentTimeMillis()){
            //获取上一步锁的时间
            String oldValue = 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 = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(currentValue) &&
                    currentValue.equals(value)){
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e){
            logger.error("【redis分布式锁】 解锁异常,{}",e);
        }
    }
}

  

具体使用的逻辑代码功能:

@Service
public class SecKillService {
    private static Logger logger = LoggerFactory.getLogger(SecKillService.class);
    /** 超时时间 */
    private static final int TIMEOUT = 10000;

    @Autowired
    private RedisLock redisLock;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private RestTemplate restTemplate;

    /**
     * @Description: 秒杀商品接口
     * @param weddingExpoAppoint
     * @return JsonObject
     * @exception
     * @author mazhq
     * @date 2018/11/18 13:46
     */
    private JsonObject seckillProduct(long productId) {
        long time = System.currentTimeMillis() + TIMEOUT;
        String stockKey = RedisKeysManager.getWeddingExpoSeckillStockKey(productId);
        //加锁
        String lockKey = "weddingExpo:seckill:"+productId;
        if (!redisLock.lock(lockKey,String.valueOf(time))){
            return BaseCode.retCode(100, "没抢到,换个姿势再来一遍");
        }

        String stockNumStr = redisClient.getStr(stockKey);
        int stockNum = 0;
        if(StringUtils.isNotBlank(stockNumStr)){
            stockNum = Integer.valueOf(stockNumStr);
        }
        JsonObject respJson = BaseCode.retCode(ResultCode.failure);
        if (stockNum == 0) {
            //库存不足
            return BaseCode.retCode(100, "商品已经被抢光了,请留意下次活动");
        } else {

            try {
                String resp = doseckill(productId);
                if(null != resp){
                    respJson = new JsonObject(resp);
                    if(respJson.getInteger("retcode") == 0){
                        redisClient.increment(stockKey, -1);
                    }
                    Thread.sleep(100);
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        //解锁
        redisLock.unlock(lockKey, String.valueOf(time));
        return respJson;
    }

}

  

主要功能描述就是:

秒杀商品时候先加锁,如果没有获取到锁就释放请求。

加锁后先进行库存判断如果不足释放请求。

进行秒杀下单流程,如果成功库存做减一操作。

最后释放分布式锁。

这样简单的分布式锁处理秒杀功能的方法就搞定了。这种只是处理高并发下多个请求如果有人在秒杀后面的直接不需排队直接释放请求,解放服务器压力(处理流程时间较短,高并发下没有排序要求)。

如果要根据请求时间进行排序,这个方式还需借助队列处理。

原文地址:https://www.cnblogs.com/owenma/p/10118935.html

时间: 2024-11-05 19:03:38

Redis分布式锁实现简单秒杀功能的相关文章

单实例redis分布式锁的简单实现

redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放. 直接上java代码, 如下: package com.test; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import jav

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

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

Redis分布式锁----乐观锁的实现,以秒杀系统为例

本文使用redis来实现乐观锁,并以秒杀系统为实例来讲解整个过程. 乐观锁      大多数是基于数据版本(version)的记录机制实现的.即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1.此时,将提交数据的版本号与数据库表对应记录的当前版本号进行比对,如果提交的数据版本号大于数据库当前版本号,则予以更新,否则认为是过期数据.redis中可以使用watch命令

Redis分布式锁解决抢购问题

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

spring boot项目之redis分布式锁的应用

SETNX key value 起始版本:1.0.0 时间复杂度:O(1) 将key设置值为value,如果key不存在,这种情况下等同SET命令. 当key存在时,什么也不做.SETNX是"SET if Not eXists"的简写. 返回值 Integer reply, 特定值: 1 如果key被设置了 0 如果key没有被设置 ##例子 redis> SETNX mykey "Hello" (integer) 1 redis> SETNX myke

redis分布式锁和消息队列

最近博主在看redis的时候发现了两种redis使用方式,与之前redis作为缓存不同,利用的是redis可设置key的有效时间和redis的BRPOP命令. 分布式锁 由于目前一些编程语言,如PHP等,不能在内存中使用锁,或者如Java这样的,需要一下更为简单的锁校验的时候,redis分布式锁的使用就足够满足了.redis的分布式锁其实就是基于setnx方法和redis对key可设置有效时间的功能来实现的.基本用法比较简单. public boolean tryLock(String lock

Redis分布式锁

转自:https://www.cnblogs.com/linjiqin/p/8003838.html 前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现

Redis分布式锁的正确实现方式

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁. 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件: 互斥性.在任意时刻,只有一个客户端能持有锁. 不会发生死锁.即使有一个客户端在

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