redis秒杀案例Demo

82 阅读2分钟

引入依赖

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>3.2.0</version>
</dependency>

秒杀分析

  • 定义缓存key
  • 获取库存,如果库存为null,返回未开始
  • 判断用书是否重复秒杀操作
  • 判断如果商品数量库存小于1,秒杀结束
  • 秒杀过程 ,1、存在减1

秒杀代码

package com.example.linqy.redis.config;

import redis.clients.jedis.Jedis;

/**
 * @author linqy
 * @version 1.0.0
 * @ClassName SeckillDemo.java
 * @Description
 * @createTime 2024年01月13日 18:19:00
 */
public class SeckillDemo {
    public static void seCcKill(String userid,String prodid) {
        Jedis jedis=new Jedis("127.0.0.1",6379);
        //定义缓存key
        String ckKey="ck:"+prodid+":qt";
        String userKey="sp:"+prodid+":user";
        //获取库存,如果库存为null,返回未开始
        String ck=jedis.get(ckKey);
        if (ck==null){
            System.out.println("秒杀还未开始");
            jedis.close();
            return;
        }
        //判断用书是否重复秒杀操作
        //判断集合 ***<key>*** 是否为含有该 ***<value>*** 值,有返回 1,没有返回 0
        if (jedis.sismember(userKey,userid)){
            System.out.println("秒杀成功,不能重复秒杀");
            jedis.close();
            return;
        }
        //判断如果商品数量库存小于1,秒杀结束
        if (Integer.parseInt(ck)<=0){
            System.out.println("秒杀已经结束");
            jedis.close();
            return;
        }
        //秒杀过程 ,1、存在减1
        jedis.decr(ckKey);
        jedis.sadd(userKey,userid);
        System.out.println("秒杀成功");
        return;
    }
}

存在超卖问题

以上代码会存在两处问题

  • 并发的时候会有链接超时问题
  • 会存在超卖问题

解决超卖问题

  • 采用连接池解决链接超时问题
  • -采用redis的事务来解决超卖问题
  1. 监听库存 String watch = jedis.watch(ckKey);
  2. 使用事务 Transaction multi = jedis.multi();
  3. 组队操作 multi.decr(ckKey); multi.sadd(userKey,userid);
  4. 执行 List exec = multi.exec();
    • 改造后代码
    package com.example.linqy.redis.config;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.Transaction;
    
    import java.util.List;
    
    /**
     * @author linqy
     * @version 1.0.0
     * @ClassName SeckillDemo.java
     * @Description
     * @createTime 2024年01月13日 18:19:00
     */
    public class SeckillDemo {
        public static void seCcKill(String userid,String prodid) {
            Jedis jedis=new Jedis("127.0.0.1",6379);
            //定义缓存key
            String ckKey="ck:"+prodid+":qt";
            String userKey="sp:"+prodid+":user";
            //监听库存
            String watch = jedis.watch(ckKey);
            //获取库存,如果库存为null,返回未开始
            String ck=jedis.get(ckKey);
    
            if (ck==null){
                System.out.println("秒杀还未开始");
                jedis.close();
                return;
            }
            //判断用书是否重复秒杀操作
            //判断集合 ***<key>*** 是否为含有该 ***<value>*** 值,有返回 1,没有返回 0
            if (jedis.sismember(userKey,userid)){
                System.out.println("秒杀成功,不能重复秒杀");
                jedis.close();
                return;
            }
            //判断如果商品数量库存小于1,秒杀结束
            if (Integer.parseInt(ck)<=0){
                System.out.println("秒杀已经结束");
                jedis.close();
                return;
            }
            //秒杀过程  
            // 使用事务
            Transaction multi = jedis.multi();
            //组对操作
            multi.decr(ckKey);
            multi.sadd(userKey,userid);
            //执行
            List<Object> exec = multi.exec();
            if (exec==null||exec.size()==0){
                System.out.println("秒杀结束");
                jedis.close();
                return;
            }
    
    
        }
    }
    
    

    引入redis的事务会存在库存遗留问题

    解决办法可以利用redis的lau语言