秒杀的思路分析 by 和奇科技

作者:和奇一号发表于:2019-05-10

  1. 需求分析:

    所谓“秒杀”,就是网络卖家发布一些超低价格的商品,所有买家在同一时间网上抢购的一种销售方式。通俗一点讲就是网络商家为促销等目的组织的网上限时抢购活动。由于商品价格低廉,往往一上架就被抢购一空,有时只用一秒钟。

    秒杀一共有,两种限制:库存限制和时间限制

    需求:

    (1)商家提交秒杀商品申请,录入秒杀商品数据,主要包括:商品标题、原价、秒杀价、商品图片、介绍等信息
    (2)运营商审核秒杀申请
    (3)秒杀频道首页列出秒杀商品(进行中的)点击秒杀商品图片跳转到秒杀商品详细页。
    (4)商品详细页显示秒杀商品信息,点击立即抢购实现秒杀下单,下单时扣减库存。当库存为 0 或不在活动期范围内时无法秒杀。
    (5)秒杀下单成功,直接跳转到支付页面(微信扫码),支付成功,跳转到成功页,填写收货地址、电话、收件人等信息,完成订单。

    (6)当用户秒杀下单 5 分钟内未支付,取消预订单,调用微信支付的关闭订单接口,恢复库存。

    数据库表的分析:

    秒杀表的数据库表,我们不放在其他的商品表中,单独设计一个表结构

    tb_seckill_goods表结构

1557470629596870.png

       tb_seckill_order表主要是:秒杀成功后生成的订单

1557470737653677.png


我们分析什么条件的商品的数据能够在秒杀页面展示?

     审核通过

      有库存

       当前实现大于开始时间,并小于秒杀结束时间   即正在秒杀的商品
 秒杀的实现思路分析:

         秒杀技术实现核心思想是运用缓存减少数据库瞬间的访问压力!读取商品详细信息时运用缓存,当用户点击抢购时减少缓存中的库存数量,当库存数为 0 时或活动期结束时,同步到数据库。 产生的秒杀预订单也不会立刻写到数据库中,而是先写到缓存,当用户付款成
功后再写入数据库。

       基于redis缓存,减少数据库的访问压力,在秒杀之前就将数据库的的数据放到缓存中

       秒杀开始后,用户抢购商品订单,下单成功后,减少库存,此时我们是操作redis中秒杀商品库存数据

那么我们在什么时候更新数据库的库存呢,      ----------------->redis库存为零,秒杀结束

使用redis缓存,单线程服务器,数据安全
定时任务spring-task实现:

定时任务主要常用的有两种:     spring - task     和quartz   

我们在这介绍spring  task   :

它可以说是轻量级的quartz    ,    主要配置文件和注解两种形式  

定时任务框架都是基于cron表达式完成定时时间指定。

往往都是6位字符
            Seconds Minutes Hours DayofMonth Month   DayofWeek
                秒    分     时     月中某天   月     周中某天   
                
                每周一凌晨1点执行任务:0 0 1 ? * 2
                
                每天15点55分执行任务:0 55 15 * * ?
                
                每月6号凌晨执行任务:0 0 0 6 * ?
                
                每隔10秒多久执行一次:0/10 0 0 * * ?
                                    
            
        注意:月中某天和周中某天只能出现一个*,不能同时为*,如果两者中有任意一个赋值,另一个往往都赋予?

 

把数据库的商品缓存到redis中 这样就能,在下单的时候通过 通过redis总访问数据

创建一个定时任务的工程  seckill_task

配置文件:

web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
 
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/applicationContext*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
 
</web-app>
-----------------------------------------------------------------

applicationContext-task .xml


  • <!--包扫描-->

  • <context:component-scan base-package="com.pinyougou.seckill.task"/>


  • <!--开启注解驱动-->

  • <task:annotation-driven/>

------------------------------------------------------


seckillTask:主要是通过定时,从数据中获得数据缓存到redis数据库中 


@Component
public class SeckillTask {
 
    @Autowired
    private TbSeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;
 
    @Scheduled(cron = "0/30 * * * * ?")//每30秒执行一次
    public  void synchronizeSeckillGoodsToRedis(){
 
        //1.查询需要秒杀的商品
        //我们把符合的商品都查询出来放到redis中
        TbSeckillGoodsExample example = new TbSeckillGoodsExample();
        TbSeckillGoodsExample.Criteria criteria = example.createCriteria();
        criteria.andStatusEqualTo("1").
                andStartTimeLessThanOrEqualTo(new Date()).
                andEndTimeGreaterThanOrEqualTo(new Date()).
                andStockCountEqualTo(0);
        List<TbSeckillGoods> seckillGoods = seckillGoodsMapper.selectByExample(example);
 
        //2.将查询的商品的数据放到redis中
        //我们将查询符合的数据放到hash格式放到redis中
        for (TbSeckillGoods seckillGood : seckillGoods) {
            redisTemplate.boundHashOps("SECKILL_GOODS").put(seckillGood.getId(),seckillGood);
            //商品的详情页,我们可以通过商品的id取值,如下就是的
           // List seckill_goods = redisTemplate.boundHashOps("SECKILL_GOODS").values();
        }
        System.out.println("synchronizeSeckillGoodsToRedis  worker  finished...");
    }
 
}
-----------------------------------------------------------

List seckill_goods = redisTemplate.boundHashOps("SECKILL_GOODS").values();

这个数据我们在秒杀的详情页中展示,所以通过上面的格式存储后,我们就可以通过商品的id取值