秒杀系统
前言
最近把redis基本的东西学的差不多了,但是没有做过什么具体的项目来实践,于是计划做一个项目来巩固知识。
本项目是一个整合springboot、mybatis、redis来做的一个秒杀系统。
1. 秒杀系统
1.1 秒杀场景
- 电商抢购限量商品
- 卖周董演唱会的门票
- 火车票抢座 12306
- …
1.2 为什么要做个系统
如果你的项目流量非常小,完全不用担心有并发的购买请求,那么做这样一个系统意义不大。但如果你的系统要像12306那样,接受高并发访问和下单的考验,那么你就需要一套完整的流程保护措施,来保证你系统在用户流量高峰期不会被搞挂了。
-
严格防止超卖:库存100件你卖了120件,等着辞职吧
-
防止黑产:防止不怀好意的人群通过各种技术手段把你本该下发给群众的利益全收入了囊中。
-
保证用户体验:高并发下,别网页打不开了,支付不成功了,购物车进不去了,地址改不了了。这个问题非常之大,涉及到各种技术,也不是一下子就能讲完的,甚至根本就没法讲完。
1.3 保护措施有哪些
乐观锁防止超卖—核心基础令牌桶限流Redis 缓存消息队列异步处理订单- …
2. 防止超卖
毕竟,你网页可以卡住最多是大家没参与到活动,上网口吐芬芳,骂你一波。但是你要是卖多了,本该拿到商品的用户可就不乐意了,轻则投诉你,重则找漏洞起诉赔偿。让你吃不了兜着走。
2.1 数据库表
-- ----------------------------
-- Table structure for stock
-- ----------------------------
DROP TABLE IF EXISTS `stock`;
CREATE TABLE `stock` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',
`count` int(11) NOT NULL COMMENT '库存',
`sale` int(11) NOT NULL COMMENT '已售',
`version` int(11) NOT NULL COMMENT '乐观锁,版本号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for stock_order
-- ----------------------------
DROP TABLE IF EXISTS `stock_order`;
CREATE TABLE `stock_order` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`sid` int(11) NOT NULL COMMENT '库存ID',
`name` varchar(30) NOT NULL DEFAULT '' COMMENT '商品名称',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.2 分析业务

2.3 开发代码
配置文件
-
DAO
public interface StockDAO { Stock checkStock(Integer id);//校验库存 void updateSale(Stock stock);//扣除库存 } public interface OrderDAO { void createOrder(Order order);//创建订单 } -
Service
@Service @Transactional public class OrderServiceImpl implements OrderService { @Autowired private OrderDAO orderDAO; @Autowired private StockDAO stockDAO; @Override public Integer createOrder(Integer id) { //校验库存 Stock stock = checkStock(id); //扣库存 updateSale(stock); //下订单 return createOrder(stock); } //校验库存 private Stock checkStock(Integer id) { Stock stock = stockDAO.checkStock(id); if (stock.getSale().equals(stock.getCount())) { throw new RuntimeException("库存不足"); } return stock; } //扣库存 private void updateSale(Stock stock){ stock.setSale(stock.getSale() + 1); stockDAO.updateSale(stock); } //下订单 private Integer createOrder(Stock stock){ Order order = new Order(); order.setSid(stock.getId()); order.setCreateDate(new Date()); order.setName(stock.getName()); orderDAO.createOrder(order); return order.getId(); } } -
Controller
@RestController @RequestMapping("stock") public class StockController { @Autowired private OrderService orderService; //秒杀方法 @GetMapping("sale") public String sale(Integer id){ int orderId = 0; try{ //根据商品id创建订单,返回创建订单的id orderId = orderService.createOrder(id); System.out.println("orderId = " + orderId); return String.valueOf(orderId); }catch (Exception e){ e.printStackTrace(); return e.getMessage(); } } }
2.4 正常测试
在正常测试下发现没有任何问题
首先在数据库中填入stock 的数据用来测试

运行程序后在浏览器输入
结果返回为
并且在stock_order表中成功生成order

本文介绍了一个基于SpringBoot、Mybatis和Redis构建的秒杀系统,旨在通过实际项目巩固Redis知识。讨论了秒杀场景,如电商抢购、门票销售等,并强调了在高并发环境下防止超卖和防止黑产的重要性。文章详细阐述了保护措施,并逐步讲解了从数据库设计到代码实现的整个过程,包括配置、DAO、Service和Controller的开发,以及测试环节。
5713





