Lua脚本实现秒杀资格判断

lua脚本

-- 1.参数列表
-- 1.1.优惠券id
local voucherId = ARGV[1]
-- 1.2.用户id
local userId = ARGV[2]
-- 1.3.订单id
local orderId = ARGV[3]

-- 2.数据key
-- 2.1.库存key
local stockKey = 'seckill:stock:' .. voucherId
-- 2.2.订单key
local orderKey = 'seckill:order:' .. voucherId

-- 3.脚本业务
-- 3.1.判断库存是否充足 get stockKey
if(tonumber(redis.call('get', stockKey)) <= 0) then
    -- 3.2.库存不足,返回1
    return 1
end
-- 3.2.判断用户是否下单 SISMEMBER orderKey userId
if(redis.call('sismember', orderKey, userId) == 1) then
    -- 3.3.存在,说明是重复下单,返回2
    return 2
end
-- 3.4.扣库存 incrby stockKey -1
redis.call('incrby', stockKey, -1)
-- 3.5.下单(保存用户)sadd orderKey userId
redis.call('sadd', orderKey, userId)
-- 消息队列一般用MQ
-- 3.6.发送消息到队列中, XADD stream.orders * k1 v1 k2 v2 ...
-- redis.call('xadd', 'stream.orders', '*', 'userId', userId, 'voucherId', voucherId, 'id', orderId)
return 0

将lua脚本放置在resources下

redisUtil,lua脚本要使用stringRedisTemplate

    /**
     * 执行lua脚本返回结果 stringRedisTemplate
     *
     * @param defaultRedisScript 脚本信息
     * @param prizeId            商品id
     * @param userId             用户id
     * @return 0=有购买资格,1=库存不足,2=不能重复下单
     */
    public Long seckillLua(DefaultRedisScript<Long> defaultRedisScript, Integer prizeId, Integer userId) {
        Long result = stringRedisTemplate.execute(
                defaultRedisScript,
                Collections.emptyList(),
                prizeId.toString(),
                userId.toString()
        );
        return result;
    }

下单Demo

    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;

    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }

    @ApiOperation("lua秒杀测试")
    @GetMapping("lua/test/{prize_id}/{user_id}")
    public ApiResponse seckill(@PathVariable("prize_id") Integer prizeId, @PathVariable("user_id") Integer userId) {
        //校验秒杀时间
        //略
        
        //使用Lua脚本校验个人资格(一人一单)
        Long result = redisUtils.seckillLua(SECKILL_SCRIPT, prizeId, userId);
        int r = result.intValue();

        if (r == 1){
            return ApiResponse.success("库存不足");
        }

        if (r == 2){
            return ApiResponse.success("不能重复下单");
        }
        if (r == 0) {
            ApiResponse.success("下单成功");
        }
        String msg = userId + "_" + prizeId;

        //发送Mq进行消息发送
        MqUtil.msgSend("TOPIC_USERNAME",msg);
        return ApiResponse.success("下单成功");
    }

猜你喜欢

转载自blog.csdn.net/m0_58709145/article/details/129688631