使用redis令牌机制实现电商秒杀

双11中本公司的一次秒杀活动(redis令牌机制)

说明:因为本公司是服务公司,不是电商公司,所以不涉及减库存等事务操作
技术选型:redis的list数据类型的"栈"特点进行,因为redis采用多路io复用,且基于内存的单线程数据库,所以程序快,且没有多线程并发引起的超卖问题,也不会有采用单纯的乐观锁实现秒杀而形成用户大量的失败问题

这里利用吃饭时间写了点简单代码代码实现,有不对的地方 可以指出

准备工作:在秒杀开始前,提前利用程序把需要秒杀的商品(服务),写进redis的list.注:一中商品(服务)一个key,如果此商品要秒杀50个,就往list中存入50个唯一标识(令牌).

1.获取令牌

public boolean miaoshaTokenFromRedis(Integer goodsId, String user) {
    String token = (String)redisTemplate.boundListOps("token_goods_"+goodsId).rightPop();
    if(token == null || token.equals("")){
        return false;
    }else{
        //记录当前用户已经抢购到令牌,证明当前这个用户可以取支付
  
        String yes  = (String)redisTemplate.boundValueOps(token).get();
        if(yes != null && yes.equals("yes")) {
            System.out.println("当前token已经被支付,不能再抢购");
            redisTemplate.boundListOps("token_goods_"+goodsId).remove(1,token);
            return false;
        }
        //value 存的对象(token,当前时间)---当前时间是跑定时任务的
        redisTemplate.boundHashOps("user_token").put(user,{token,new Date()});
        return true;
    }
}

2.退还令牌(定时任务每5s执行一次)

public boolean returnToken(String user) {
    //获得当前用户的令牌
    String token =  (String) redisTemplate.boundHashOps("user_token").get(user);
    if(token == null || token.equals("")){
        return false;
    }else {
        //得到商品id并从新存入list中 其他人可以抢购
        String goodsId = token.split("_")[1];
        redisTemplate.boundListOps("token_goods_"+goodsId).leftPush(token);
        return true;
    }
}

3.成功支付

public boolean payTokenToOrder(String user) {
    //获得当前用户的令牌
    String token =  (String) redisTemplate.boundHashOps("user_token").get(user);
    if(token == null || token.equals("")){
        return false;
    }else {
        //如果在当前token已经被购买过,那么别人就不能抢当前的token或者不能再对该token进行支付
        //采用redis记录当前token已经被支付
        //redisTemplate.boundValueOps("key").setIfAbsent("value")
        //如果当前这个key有值,该方法就会返回false,如果没有值,就会s设置为对应value,同时返回true
        boolean flag = redisTemplate.boundValueOps(token).setIfAbsent("yes");
        //当前token第一次被支付 flag=true
        if(flag) {
            //得到商品(f服务)id
            String goodsId = token.split("_")[1];
            Order order = new Order();
            order.setUser(user);
            order.setGoodId(Integer.parseInt(goodsId));
            orderMapper.insert(order);
            //用户刚好在支付时,定时任务执行,保证用户支付成功,所以删除一次
            redisTemplate.boundHashOps("user_token").delete(user);//有可能已经归还token

            redisTemplate.boundListOps("token_goods_" + goodsId).remove(1, token);//移除token, 有可能被别人抢到
        }
        return true;
    }
}

你可能感兴趣的