基于RocketMQ设计秒杀

环境介绍

服务器: 阿里云Centos7.4

JDK版本: jdk1.8
RocketMQ版本: 4.5.1

安装RocketMQ
wget https://archive.apache.org/dist/rocketmq/4.5.1/rocketmq-all-4.5.1-bin-release.zip
启动nameserver
# 1.启动
NameServermqnamesrv
# 2.查看启动日志
tail -f ~/logs/rocketmqlogs/namesrv.log
启动broker
mqbroker -n localhost:9876
# 2.查看启动日志
tail -f ~/logs/rocketmqlogs/broker.log
基于RocketMQ设计秒杀实现逻辑

在这里插入图片描述
这里的超时支付使用redis过期回调处理

核心代码 :


@Component
@RocketMQMessageListener(topic = "springboot-mq",consumerGroup = "springboot-mq-consumer-1")
public class Consumer implements RocketMQListener<OrderInfo> {

    @Resource
    OrderInfoMapper orderInfoMapper;
    @Resource
    WarehouseMapper warehouseMapper;
    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public void onMessage(OrderInfo orderInfo) {
        System.out.println("消费订单消息");

        orderInfoMapper.insert(orderInfo);
        System.out.println(orderInfo.getId()+"订单入库");
        Warehouse warehouse = warehouseMapper.selectByPrimaryKey(orderInfo.getCommodity());
        warehouse.setNum(warehouse.getNum()-1);
        System.out.println("扣减库存");
        warehouseMapper.updateByPrimaryKey(warehouse);

        redisTemplate.opsForValue().set("order:"+orderInfo.getId(),"",15,TimeUnit.SECONDS);

    }

}

@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    @Resource
    OrderInfoMapper orderInfoMapper;
    @Resource
    WarehouseMapper warehouseMapper;
    @Autowired
    StringRedisTemplate redisTemplate;


    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    public void onMessage(Message message, byte[] pattern) {

        String expireKey = message.toString();

        if (expireKey.startsWith("order:")){

            Integer orderId = Integer.valueOf(expireKey.replace("order:",""));

            OrderInfo orderInfo = orderInfoMapper.selectByPrimaryKey(orderId);
            orderInfo.setStatus(2);
            orderInfoMapper.updateByPrimaryKeySelective(orderInfo);
            System.out.println("订单失效,库存还原+1");
            Warehouse warehouse = warehouseMapper.selectByPrimaryKey(orderInfo.getCommodity());
            warehouse.setNum(warehouse.getNum()+1);
            warehouseMapper.updateByPrimaryKey(warehouse);

            redisTemplate.opsForValue().increment("num");
        }
    }

}
@Service
public class OrderService {

    @Resource
    OrderInfoMapper orderInfoMapper;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;



    public Integer submitOrder(Integer commodity){
        Integer id = getOrderNum();
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(id);
        orderInfo.setCommodity(commodity);
        orderInfo.setStatus(0);

        boolean flag = subtractStock(1);

        if(!flag){
            return -1;
        }
        rocketMQTemplate.convertAndSend("springboot-mq",orderInfo);

        return id;
    }

    public Integer pay(Integer id){
        Boolean delete = redisTemplate.delete("order:" + id);
        System.out.println(delete);
        if(delete){
            return 1;
        }
        return 0;
    }

    /**
     * 模拟订单号
     * @return
     */
    public Integer getOrderNum(){
        Random random = new Random();
        return random.nextInt(10000);
    }

    /**
     * Redis乐观锁实现秒杀
     * @param num
     * @return
     */
    public boolean subtractStock(Integer num) {
        String key = "num";
        redisTemplate.setEnableTransactionSupport(true);
        redisTemplate.watch(key);

        Object value = redisTemplate.opsForValue().get(key);
        if (value == null) {
            //前提 提前将商品库存放入缓存 ,如果缓存不存在,视为没有该商品
            return false;
        }
        //先检查 库存是否充足
        Integer stock = Integer.valueOf(value.toString());

        if (stock < num) {
            System.out.println("库存不足");
            return false;
        }

        redisTemplate.multi();
        Long newStock = redisTemplate.opsForValue().increment(key, -num.longValue());
        System.out.println(newStock);
        List<Object> exec = redisTemplate.exec();

        if(exec!=null && exec.size()>0){
            return true;
        }

        return false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值