Redis和请求队列解决高并发

准备工作,查询商品信息,将剩余数量同步到redis中

Jedis jedis = jedisPool.getResource();
BuyGood good=buyGoodService.getById(good_id);
jedis.set("residue"+good_id, good.getResidue()+"");
jedisPool.returnResource(jedis);

请求封装对象

public class BuyRequest {
    private int good_id;//商品id
    private int user_id;//用户ID
    private int order_id;//订单id
    private BuyOrders buyOrders;//订单信息
    private int response_status;//0:未处理;1:正常;2:异常

    public BuyOrders getBuyOrders() {
        return buyOrders;
    }

    public void setBuyOrders(BuyOrders buyOrders) {
        this.buyOrders = buyOrders;
    }


    public int getGood_id() {
        return good_id;
    }

    public void setGood_id(int good_id) {
        this.good_id = good_id;
    }

    public int getOrder_id() {
        return order_id;
    }

    public void setOrder_id(int order_id) {
        this.order_id = order_id;
    }

    public int getResponse_status() {
        return response_status;
    }

    public void setResponse_status(int response_status) {
        this.response_status = response_status;
    }

    public int getUser_id() {
        return user_id;
    }

    public void setUser_id(int user_id) {
        this.user_id = user_id;
    }
}

处理请求的controller

@Controller
@RequestMapping("/buy")
public class BuyController {

    private static BuyQueue<BuyRequest> buyqueue =null;//线程安全的请求队列

@RequestMapping("/addOrders.do")
    @ResponseBody
    public Object addOrders(BuyRequest buyrequest){
        Map<String, Object> results = new HashMap<>();
        Jedis jedis = jedisPool.getResource();
        try {
            //下订单之前,先获取商品的剩余数量
        int residue = Integer.valueOf(jedis.get("residue"+buyrequest.getGood_id()));
        if(residue<1){//如果剩余数量不足,直接响应客户端“卖完了”
            results.put("msg", "卖完了");
            results.put("done", false);
            BaseLog.info("addOrders results="+JSON.toJSONString(results)); 
            return results;
        }
        //如果还有剩余商品,就准备将请求放到请求队列中
        if(buyqueue==null){//第一次初始化请求队列,队列的容量为当前的商品剩余数量
            buyqueue=new BuyQueue<BuyRequest>(residue);
            }
        if(buyqueue.remainingCapacity()>0){//当队列的可用容量大于0时,将请求放到请求队列中
            buyqueue.put(buyrequest);
        }else{//当请求队列已满,本次请求不能处理,直接响应客户端提示请求队列已满
            results.put("msg", "抢购队列已满,请稍候重试!");
            results.put("done", false);
            return results;
        }

        if(!DealQueueThread.excute){//如果线程类的当前执行标志为未执行,即空闲状态,通过线程池启动线程
        DealQueueThread dealQueue = new DealQueueThread(buyqueue);
        ThreadPoolUtil.pool.execute(dealQueue);
        BaseLog.info("Thread.activeCount()="+Thread.activeCount());
        }
       //请求放入到队列中,即完成下单请求
            results.put("done", true);
            results.put("msg", "下订单成功");

        } catch (Exception e) {
            results.put("done", false);
            results.put("msg", "下单失败");
            BaseLog.info("addOrders results="+JSON.toJSONString(results)); 
            BaseLog.error("addOrders",e);
        }finally{
            jedisPool.returnResource(jedis);
        }
        return results;
    }

}

处理请求的线程类

@Component
public class DealQueueThread implements Runnable {

    private static DealQueueThread dealQueueThread;
    @Autowired
    BuyGoodService buyGoodService;
    @Autowired
    BuyOrdersService buyOrdersService;
    @Autowired
    JedisPool jedisPool;

    private Jedis jedis;

    private BuyQueue<BuyRequest> buyqueue;

    public static boolean excute = false;//线程的默认执行标志为未执行,即空闲状态

    public DealQueueThread() {

    }

    public DealQueueThread(BuyQueue<BuyRequest> buyqueue) {
        this.buyqueue = buyqueue;
        jedis = dealQueueThread.jedisPool.getResource();
    }

    @PostConstruct
    public void init() {
        dealQueueThread = this;
        dealQueueThread.buyGoodService = this.buyGoodService;
        dealQueueThread.buyOrdersService = this.buyOrdersService;
        dealQueueThread.jedisPool = this.jedisPool;
    }

    @Override
    public void run() {
        try {
            excute = true;//修改线程的默认执行标志为执行状态
            //开始处理请求队列中的请求,按照队列的FIFO的规则,先处理先放入到队列中的请求
            while (buyqueue != null && buyqueue.size() > 0) {
                BuyRequest buyreq = buyqueue.take();//取出队列中的请求
                dealWithQueue(buyreq);//处理请求
            }
        } catch (InterruptedException e) {
            BaseLog.error("DealQueueThread:", e);
        } finally {
            excute = false;
        }
    }

    public synchronized void dealWithQueue(BuyRequest buyreq) {
        try {
            //为了尽量确保数据的一致性,处理之前先从redis中获取当前抢购商品的剩余数量
            int residue = Integer.valueOf(jedis.get("residue" + buyreq.getGood_id()));
            if (residue < 1) {//如果没有剩余商品,就直接返回
                buyreq.setResponse_status(3);
                return;
            }
            //如果有剩余商品,先在redis中将剩余数量减一,再开始下订单
            jedis.decr("residue" + buyreq.getGood_id());
            //将数据库中将剩余数量减一,这一步处理可以在队列处理完成之后一次性更新剩余数量
            dealQueueThread.buyGoodService.minusResidue(buyreq.getGood_id());

            //处理请求,下订单
            BuyOrders bo = new BuyOrders();
            bo.setGood_id(buyreq.getGood_id());
            bo.setUser_id(buyreq.getUser_id());
            int order_id = dealQueueThread.buyOrdersService.insert(bo);
            BuyOrders orders = dealQueueThread.buyOrdersService.getById(order_id);
            buyreq.setOrder_id(order_id);//订单id
            buyreq.setBuyOrders(orders);//订单信息
            buyreq.setResponse_status(1);//处理完成状态
        } catch (Exception e) {
            buyreq.setResponse_status(2);//异常状态
            BaseLog.error("DealQueueThread dealWithQueue:", e);
        }
    }

}

 BuyQueue:

public class BuyQueue extends ArrayBlockingQueue<BuyRequest> { 
     public BuyQueue(int capacity) { 
         super(capacity); 
     } 
}

 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值