秒杀业务分析

目录

秒杀

1 秒杀业务分析

1.1 需求分析

1.2 表结构说明

       秒杀订单表

2 秒杀商品压入缓存

秒杀商品压入缓存

2.1 秒杀服务工程

2.2 定时任务

2.3 秒杀商品压入缓存实现

3 秒杀频道页​

概述

3.1 秒杀时间菜单

3.2 秒杀频道页

4 秒杀详情页

概述

5 下单实现

6 多线程抢单​

6.1 实现思路分析

6.2 异步实现

6.3 多线程抢单​


秒杀

1 秒杀业务分析

1.1 需求分析

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

  • 秒杀商品通常有两种限制:库存限制、时间限制。

  • 需求:

    • (1)录入秒杀商品数据,主要包括:商品标题、原价、秒杀价、商品图片、介绍、秒杀时段等信息

    • (2)秒杀频道首页列出秒杀商品(进行中的)点击秒杀商品图片跳转到秒杀商品详细页。

    • (3)商品详细页显示秒杀商品信息,点击立即抢购实现秒杀下单,下单时扣减库存。当库存为0或不在活动期范围内时无法秒杀。

    • (4)秒杀下单成功,直接跳转到支付页面(扫码),支付成功,跳转到成功页,填写收货地址、电话、收件人等信息,完成订单。

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

1.2 表结构说明

        秒杀商品信息表

CREATE TABLE `tb_seckill_goods` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `goods_id` bigint(20) DEFAULT NULL COMMENT 'spu ID',
  `item_id` bigint(20) DEFAULT NULL COMMENT 'sku ID',
  `title` varchar(100) DEFAULT NULL COMMENT '标题',
  `small_pic` varchar(150) DEFAULT NULL COMMENT '商品图片',
  `price` decimal(10,2) DEFAULT NULL COMMENT '原价格',
  `cost_price` decimal(10,2) DEFAULT NULL COMMENT '秒杀价格',
  `create_time` datetime DEFAULT NULL COMMENT '添加日期',
  `check_time` datetime DEFAULT NULL COMMENT '审核日期',
  `status` char(1) DEFAULT NULL COMMENT '审核状态,0未审核,1审核通过,2审核不通过',
  `start_time` datetime DEFAULT NULL COMMENT '开始时间',
  `end_time` datetime DEFAULT NULL COMMENT '结束时间',
  `num` int(11) DEFAULT NULL COMMENT '秒杀商品数',
  `stock_count` int(11) DEFAULT NULL COMMENT '剩余库存数',
  `introduction` varchar(2000) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

       秒杀订单表

CREATE TABLE `tb_seckill_order` (
  `id` bigint(20) NOT NULL COMMENT '主键',
  `seckill_id` bigint(20) DEFAULT NULL COMMENT '秒杀商品ID',
  `money` decimal(10,2) DEFAULT NULL COMMENT '支付金额',
  `user_id` varchar(50) DEFAULT NULL COMMENT '用户',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',
  `status` char(1) DEFAULT NULL COMMENT '状态,0未支付,1已支付',
  `receiver_address` varchar(200) DEFAULT NULL COMMENT '收货人地址',
  `receiver_mobile` varchar(20) DEFAULT NULL COMMENT '收货人电话',
  `receiver` varchar(20) DEFAULT NULL COMMENT '收货人',
  `transaction_id` varchar(30) DEFAULT NULL COMMENT '交易流水',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2 秒杀商品压入缓存

秒杀商品压入缓存

  • 我们这里秒杀商品列表和秒杀商品详情都是从Redis中取出来的,所以我们首先要将符合参与秒杀的商品定时查询出来,并将数据存入到Redis缓存中。

  • 数据存储类型我们可以选择Hash类型。

  • 秒杀分页列表这里可以通过获取redisTemplate.boundHashOps(key).values()获取结果数据。

  • 秒杀商品详情,可以通过redisTemplate.boundHashOps(key).get(key)获取详情。

2.1 秒杀服务工程

  • 我们将商品数据压入到Reids缓存,可以在秒杀工程的服务工程中完成,可以按照如下步骤实现:

    • 1.查询活动没结束的所有秒杀商品

      • 1)状态必须为审核通过 status=1

      • 2)商品库存个数>0

      • 3)活动没有结束 endTime>=now()

      • 4)在Redis中没有该商品的缓存

      • 5)执行查询获取对应的结果集

    • 2.将活动没有结束的秒杀商品入库

2.2 定时任务

  • 我们采用Spring的定时任务定时将符合参与秒杀的商品查询出来再存入到Redis缓存,所以这里需要使用到定时任务。

  • 这里我们了解下定时任务相关的配置,配置步骤如下:

    • 1)在定时任务类的指定方法上加上@Scheduled开启定时任务

    • 2)定时任务表达式:使用cron属性来配置定时任务执行时间

2.3 秒杀商品压入缓存实现

  • 2.3.1 数据检索条件分析

    • 按照2.1中的几个步骤实现将秒杀商品从数据库中查询出来,并存入到Redis缓存

      • 1.查询活动没结束的所有秒杀商品

        • 1)计算秒杀时间段

        • 2)状态必须为审核通过 status=1

        • 3)商品库存个数>0

        • 4)活动没有结束 endTime>=now()

        • 5)在Redis中没有该商品的缓存

        • 6)执行查询获取对应的结果集

      • 2.将活动没有结束的秒杀商品入库

  • 2.3.2 时间菜单分析

    • 我们将商品数据从数据库中查询出来,并存入Redis缓存,但页面每次显示的时候,只显示当前正在秒杀以及往后延时2个小时、4个小时、6个小时、8个小时的秒杀商品数据。我们要做的第一个事是计算出秒杀时间菜单,这个菜单是从后台获取的。

    • 而现实的菜单只需要计算出当前时间在哪个时间段范围,该时间段范围就属于正在秒杀的时间段,而后面即将开始的秒杀时间段的计算也就出来了,可以在当前时间段基础之上+2小时、+4小时、+6小时、+8小时。

  • 2.3.3 查询秒杀商品导入Reids

    • 我们可以写个定时任务,查询从当前时间开始,往后延续4个时间菜单间隔,也就是一共只查询5个时间段抢购商品数据,并压入缓存

3 秒杀频道页

概述

  • 秒杀频道首页,显示正在秒杀的和未开始秒杀的商品(已经开始或者还没开始,未结束的秒杀商品)

3.1 秒杀时间菜单

  • 时间菜单需要根据当前时间动态加载,时间菜单的计算上面功能中已经实现,在DateUtil工具包中。我们只需要将时间菜单获取,然后响应到页面,页面根据对应的数据显示即可。

3.2 秒杀频道页

  • 秒杀频道页是指将对应时区的秒杀商品从Reids缓存中查询出来,并到页面显示。对应时区秒杀商品存储的时候以Hash类型进行了存储,key=SeckillGoods_2019010112,value=每个商品详情。

  • 每次用户在前端点击对应时间菜单的时候,可以将时间菜单的开始时间以yyyyMMddHH格式提交到后台,后台根据时间格式查询出对应时区秒杀商品信息。

4 秒杀详情页

概述

  • 通过秒杀频道页点击请购按钮,会跳转到商品秒杀详情页,秒杀详情页需要根据商品ID查询商品详情,我们可以在频道页点击秒杀抢购的时候将ID一起传到后台,然后根据ID去Redis中查询详情信息。

5 下单实现

用户下单,从控制层->Service层->Dao层

用户下单,为了提升下单速度,我们将订单数据存入到Redis缓存中,如果用户支付了,则将Reids缓存中的订单存入到MySQL中,并清空Redis缓存中的订单。

6 多线程抢单

6.1 实现思路分析

  • 下订单这里,我们一般采用多线程下单,但多线程中我们又需要保证用户抢单的公平性,也就是先抢先下单。我们可以这样实现,用户进入秒杀抢单,如果用户符合抢单资格,只需要记录用户抢单数据,存入队列,多线程从队列中进行消费即可,存入队列采用左压,多线程下单采用右取的方式。

6.2 异步实现

  • 要想使用Spring的异步操作,需要先开启异步操作,用@EnableAsync注解开启,然后在对应的异步方法上添加注解@Async即可。

6.3 多线程抢单

  • 用户每次下单的时候,我们都让他们先进行排队,然后采用多线程的方式创建订单,排队我们可以采用Redis的队列实现,多线程下单我们可以采用Spring的异步实现。

  • 6.3.1 多线程下单

  • 6.3.2 排队下单

    • 6.3.2.1 排队信息封装

      • 用户每次下单的时候,我们可以创建一个队列进行排队,然后采用多线程的方式创建订单,排队我们可以采用Redis的队列实现。 排队信息中需要有用户抢单的商品信息,主要包含商品ID,商品抢购时间段,用户登录名。我们可以设计个javabean

    • 6.3.2.2 排队实现

      • 我们可以将秒杀抢单信息存入到Redis中,这里采用List方式存储,List本身是一个队列,用户点击抢购的时候,就将用户抢购信息存入到Redis中

      • 多线程每次从队列中获取数据,分别获取用户名和订单商品编号以及商品秒杀时间段,进行下单操作

  • 6.3.3 下单状态查询

    • 按照上面的流程,虽然可以实现用户下单异步操作,但是并不能确定下单是否成功,所以我们需要做一个页面判断,每过1秒钟查询一次下单状态,多线程下单的时候,需要修改抢单状态,支付的时候,清理抢单状态。

    • 6.3.3.1 下单更新抢单状态

      • 用户每次点击抢购的时候,如果排队成功,则将用户抢购状态存储到Redis中,多线程抢单的时候,如果抢单成功,则更新抢单状态。

    • 6.3.3.2 后台查询抢单状态

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xinyi_java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值