redis秒杀简单实现

redis两个key,一个key采用string 记录库存,另一个key使用list记录秒杀成功的用户

基本流程:

1、一个请求带着用户信息过来

2、获取库存

3、判断库存是否>0

4、大于并判断该用户是否已经存在,不存在则保存用户信息,存在则返回已经成功秒杀。

5、否则秒杀失败

代码实现一:

@GetMapping("/seckill")
    public String seckill(String name) {
        log.info(name + "来了");
        String product_number = redisTemplate.opsForValue().get("product_number");
        int num = Integer.parseInt(product_number);
        if (num <= 0) {
            return "商品已被抢光";
        }
        if (redisTemplate.opsForSet().isMember("product_list", name)) {
            return "已经抢过了";
        }
        redisTemplate.opsForValue().decrement("product_number");
        redisTemplate.opsForSet().add("product_list", name);
        return "成功";
    }

上述流程会出现超卖的情况,必须保证整个查询库存,减少库存,设置用户信息的原子性,才不或出现上述情况

采用lua脚本保证:

代码实现二:

@GetMapping("/seckill2")
    public String seckill2(String name) {
        log.info(name + "来了");
        List<String> keys = Arrays.asList(name);
        Long execute = redisTemplate.execute(getRedisScript, keys);
        if (execute == 1) {
            log.info("抢成功");
            return "成功";
        } else if (execute == 2) {
            log.info("已经抢到了");
            return "已经抢过了";
        } else if (execute == 0) {
            log.info("已经抢光了");
            return "抢光了";
        }
        return "成功";
    }

    @PostConstruct
    public DefaultRedisScript<Long> getscript() {
        getRedisScript = new DefaultRedisScript<Long>();
        getRedisScript.setResultType(Long.class);
        getRedisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/product.lua")));
        return getRedisScript;
    }

lua脚本:

local name=KEYS[1];

local userExists=redis.call("sismember","product_list",name);

if tonumber(userExists)==1
then
    return 2;
end

local num =redis.call("get","product_number")

if tonumber(num)<=0
then
    return 0;
end

redis.call("decr","product_number")
redis.call("sadd","product_list",name)
return 1;

results matching ""

    No results matching ""