redis实现秒杀
背景:
某电商网站实现秒杀功能,用户在某个时间段内能够抢购到特价商品,且某一商品最多只能被同一用户抢购一次。
基本思路:
- 秒杀商品由商家后台添加,秒杀商品数据保存在tb_seckilll_goods表中,关键字段包括:
- id,status(审核状态),start_time(开始时间),end_time(结束时间),stock_count(库存量);
- 写一个定时器,定时从秒杀商品表中扫描数据,将符合条件的商品加载到缓存中;条件:审核状态="1",start_time < 当前时间 < end_time,库存量大于0;
- 前端展示,此处略
- 点击抢购,拿着秒杀商品的id去缓存中查询,如果缓存中商品不存在或者为空,提示“已售罄”,否则生成订单,保存到缓存中,订单表tb_seckill_order
- 库存-1,判断减完之后缓存中商品的库存是否大于0,大于0则更新缓存,否则删除该秒杀商品的缓存,并更新到数据库
技术选型:缓存redis,定时器:spring整合quartz
如下完成了一个基本的秒杀下单的业务:
扫描秒杀商品加载到redis:
@Scheduled(cron = "0 */1 * * * ?")//cron表达式:每分钟执行一次,周期可任意定义
public void importToRedis(){
//1.查询合法秒杀商品数据
TbSeckillGoodsExample example = new TbSeckillGoodsExample();
Date date = new Date();
example.createCriteria().andStatusEqualTo("1").andStockCountGreaterThan(0)
.andStartTimeLessThan(date).andEndTimeGreaterThan(date);
List<TbSeckillGoods> tbSeckillGoods = seckillGoodsMapper.selectByExample(example);
for (TbSeckillGoods seckillGood : tbSeckillGoods) {//将秒杀商品依次存入redis
//注意如果redis中已经有的商品,则不更新,只添加之前未加入过的秒杀商品
if(redisTemplate.boundHashOps("TbSeckillGoods").get(seckillGood.getId()) == null){
redisTemplate.boundHashOps("TbSeckillGoods").put(seckillGood.getId(), seckillGood);
}
}
}
对所有的秒杀商品都使用同一个key:“TbSeckillGoods”,值的存储类型为hash
下单的service代码:
public Result saveOrder(Long id, String userId) {
//根据商品id从redis中查出商品