Java基于redis和mysql实现简单的秒杀(附demo)

作者:JAVA拾贝 时间:2024-01-16 16:55:13 

一.秒杀业务分析

       所谓秒杀,就是网络卖家发布一些超低价格的商品,所有买家在同一时间网上抢购的一种销售方式。秒杀商品通常有两种限制:时间限制,库存限制,其中库存超卖问题是本教程的重点!

秒杀业务的运行流程主要可以分为以下几点:

  • 商家提交秒杀商品申请,录入秒杀商品数据,主要有:商品标题,商品原价,秒杀价格,商品图片,介绍等信息

  • 运营商审核秒杀申请

  • 秒杀频道首页列出秒杀商品,点击秒杀商品图片可以跳转到秒杀商品详细页面

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

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

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

 二.数据库设计

商品表:

Java基于redis和mysql实现简单的秒杀(附demo)

订单表:

Java基于redis和mysql实现简单的秒杀(附demo)

  三.秒杀实现思路

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

  四.实现关键步骤说明

缓存商品信息,库存信息


 @Override
 @Transactional(rollbackFor = Exception.class)
 public GoodsEntity initGoods(String name, Integer amount, BigDecimal price) {
   GoodsEntity goodsEntity = new GoodsEntity().setName(name).setAmount(amount).setPrice(price).setStartDate(new Date()).setEndDate(new Date());
   Assert.isTrue(goodsService.save(goodsEntity), "抢购商品初始化发生异常~");
   // 缓存库存
   redisTemplate.opsForValue().increment("amount:" + goodsEntity.getId(), amount);
   // 缓存商品信息
   redisTemplate.opsForValue().set("goods:" + goodsEntity.getId(), goodsEntity);
   return goodsEntity;
 }

基于redis incr 原子性防止超卖


 @Override
 @Transactional(rollbackFor = Exception.class)
 public Boolean secKill(String key) {
   Long result = redisTemplate.opsForValue().decrement("amount:" + key, 1);
   if (result.compareTo(0L) >= 0) {
     // 下面的数据库操作建议走MQ让数据库按照他的处理能力,从消息队列中拿取消息进行处理。
     Try.of(() -> {
       Assert.isTrue(goodsService.secKill(Long.valueOf(key)), "库存不足!");
       OrderEntity orderEntity = new OrderEntity().setGoodsId(Long.valueOf(key)).setOrderNo(UUID.randomUUID().toString().replace("-", ""));
       Assert.isTrue(orderService.save(orderEntity), "订单创建发生异常~");
       redisTemplate.opsForValue().set("secKill:" + orderEntity.getId(), orderEntity.getOrderNo(), 10, TimeUnit.SECONDS);
       return true;
     }).onFailure((e) -> {
       log.error("持久化异常:" + e.getMessage());
       redisTemplate.opsForValue().increment("amount:" + key, 1);
     });
     return false;
   }
   redisTemplate.opsForValue().increment("amount:" + key, 1);
   return false;
 }

 最终效果:

Java基于redis和mysql实现简单的秒杀(附demo)

Java基于redis和mysql实现简单的秒杀(附demo)

观察redis存储的数据和数据库的订单记录可发现,秒杀场景基本实现!

四.总结

     本文主要解决超卖,和长时间未支付库存重置的问题; 实际场景,还要考虑前后端的多种优化(静态页、cdn、防止重复下单、限流等等……)

五.完整代码示例

前往下载

来源:https://blog.csdn.net/kuangni5808/article/details/109578241

标签:Java,redis,mysql,秒杀
0
投稿

猜你喜欢

  • Python中asyncio模块的深入讲解

    2022-05-18 22:33:53
  • Python数据类型转换实现方法

    2022-06-04 22:58:39
  • JS求1到任意数之间的所有质数的方法详解

    2023-06-28 11:46:06
  • javascript 自动转到命名锚记

    2024-04-29 13:44:46
  • SQL中查找某几个字段完全一样的数据

    2024-01-26 12:55:59
  • 教你学会通过python的matplotlib库绘图

    2022-03-04 13:08:52
  • 巧用一条SQL 实现其它进制到十进制转换

    2009-01-19 13:16:00
  • 基于Python预测一下世界杯最后赢家

    2021-01-30 16:16:48
  • 关于 MySQL 嵌套子查询中无法关联主表字段问题的解决方法

    2024-01-18 23:05:28
  • 使SQL用户只能看到自己拥有权限的库(图文教程)

    2024-01-27 11:07:27
  • python中defaultdict方法的使用详解

    2022-06-25 05:07:09
  • python实现图片九宫格分割的示例

    2021-02-08 22:19:38
  • python标识符命名规范原理解析

    2023-05-28 04:06:42
  • MySql数据库基本命令集会

    2011-08-05 18:43:23
  • 大数据量,海量数据处理方法总结

    2024-01-12 21:59:38
  • Mysql联合查询UNION和Order by同时使用报错问题的解决办法

    2024-01-12 18:44:35
  • 浅谈javascript:两种注释,声明变量,定义函数

    2024-04-16 09:06:06
  • php中如何判断一个网页请求是ajax请求还是普通请求

    2023-10-13 14:42:30
  • Python实现快速多线程ping的方法

    2023-05-28 21:35:09
  • Python-jenkins 获取job构建信息方式

    2022-01-11 19:06:17
  • asp之家 网络编程 m.aspxhome.com