# 秒杀系统 **Repository Path**: carpedil/second-kill-system ## Basic Information - **Project Name**: 秒杀系统 - **Description**: No description available - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-02-07 - **Last Updated**: 2024-12-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 秒杀系统 ## 应用场景 - 电商抢购限量商品 - 明星演唱会门票 - 火车票12306 - .... # 为什么要做个系统 ```Java 如果项目的流量非常小,完全不担心有并发的购买请求,那么做这个秒杀系统意义不大,但是如果项目的系统要像12306那样,接收高并发和下单的考验,那么就需要一套完整的流程保护措施 那么一个秒杀系统完整的保护流程应该有以下几个方面: 1.严格防止超卖: 库存100,但是卖了1000件,等着跟用户扯皮吧 2.防止黑产: 防止不怀好意的人群通过技术手段,把本来应该发给客户群体的利益收入囊中 3.保证用户体验: 高并发下,别网页打不开了,支付不了,购物车进不去,地址改不了等等 ``` # 保护措施 - 乐观锁防止超卖 (悲观锁`同步代码块`也可以解决超卖,但是不推荐) - 令牌桶限流 - redis 缓存 - 消息队列异步处理订单 > 悲观锁防止超卖代码实现 ```java // 控制层 @GetMapping("kill") public String stockKill(Integer id){ System.out.println("商品id = "+id); try{ // 使用悲观锁防止超卖,但是不推荐这种方式,效率很低 synchronized (this){ // 调用秒杀业务 return"秒杀成功:"+String.valueOf(orderService.kill(id)); } }catch(Exception e){ e.printStackTrace(); return e.getMessage(); } } // 业务层 @Override @Transactional(rollbackFor = Exception.class) public int kill(Integer id){ // 根据商品id校验库存 Stock stock=stockMapper.checkStockById(id); if(stock.getCount().equals(stock.getSale())){ throw new RuntimeException("库存不足"); }else{ // 减扣库存 stock.setSale(stock.getSale()+1); stockMapper.updateStock(stock); // 创建订单 Order order= new Order() .setSid(stock.getId()) .setName(stock.getName()) .setCreateTime(LocalDateTime.now()); orderMapper.createOrder(order); return order.getId(); } } ``` ```xml update stock set sale = #{sale} where id = #{id} and version = #{version} ``` > 乐观锁防止超卖代码实现 > 先将业务层代码进行拆分,分步实现,主要区别在减扣库存,悲观锁是从Java代码层面实现库存减扣 > 乐观锁是在sql语句层面实现减扣库存,同时加入了版本号,利用的是数据库在操作的时候,会对被操作的资源进行加锁的特性实现的(事务) ```java // 校验库存 private Stock checkStock(Integer id){ // 根据商品id校验库存 Stock stock=stockMapper.checkStockById(id); if(stock.getCount().equals(stock.getSale())){ throw new RuntimeException("库存不足"); } return stock; } // 减扣库存 private void updateSale(Stock stock){ // 减扣库存 int updateRowCount=stockMapper.updateStock(stock); if(updateRowCount==0){ throw new RuntimeException("抢购失败"); } } // 创建订单 ``` > 令牌桶限流 ```xml com.google.guava guava 28.2-jre ``` ```java /** 创建令牌桶实例 设置初始令牌数:10个 */ private RateLimiter rateLimiter=RateLimiter.create(20); @GetMapping("killToken") public String stockKillToken(Integer id){ System.out.println("商品id = "+id); if(rateLimiter.tryAcquire(3,TimeUnit.SECONDS)){ log.info("活动过于火爆,服务器爆满,请求被抛弃,请重试!!!"); return"抢购失败,活动过于火爆,服务器爆满,请重试!!!"; } try{ // 调用秒杀业务 return"秒杀成功:"+String.valueOf(orderService.kill(id)); }catch(Exception e){ e.printStackTrace(); return e.getMessage(); } } ```