SpringBoot秒杀系统实战14-秒杀功能的实现(秒杀业务逻辑处理)
2020-07-14 06:02
423 查看
文章目录
先去设置数据库里面的秒杀时间
假设当前时间是2020-05-08 19:30:12
1.已经开始
2.秒杀结束
3.秒杀倒计时
所以我们去秒杀第一个商品:
在之前的goods_detail.html里面的秒杀按钮点击之后提交/miaosha/do_miaosha,以POST类型提交,带有数据是秒杀商品的goodsId
1、 新建一个MiaoshaController,定义接收该秒杀请求的接口方法doMiaosha
我们秒杀成功之后,那么会直接进入订单的详情页,所以我们秒杀成功后直接返回订单信息,并且返回值订单页面。
MiaoshaController代码:
[code] @RequestMapping("/miaosha") @Controller public class MiaoshaController{ @Autowired GoodsService goodsService; @Autowired RedisService redisService; @Autowired MiaoshaService miaoshaService; @Autowired OrderService orderService; @RequestMapping("/do_miaosha") public String toList(Model model,MiaoshaUser user,@RequestParam("goodsId") Long goodsId) { model.addAttribute("user", user); //如果用户为空,则返回至登录页面 if(user==null){ return "login"; } GoodsVo goodsvo=goodsService.getGoodsVoByGoodsId(goodsId); //判断商品库存,库存大于0,才进行操作,多线程下会出错 int stockcount=goodsvo.getStockCount(); if(stockcount<=0) {//失败 库存至临界值1的时候,此时刚好来了加入10个线程,那么库存就会-10 model.addAttribute("errorMessage", CodeMsg.MIAOSHA_OVER_ERROR); return "miaosha_fail"; } //判断这个秒杀订单形成没有,判断是否已经秒杀到了,避免一个账户秒杀多个商品 MiaoshaOrder order=orderService.getMiaoshaOrderByUserIdAndGoodsId(user.getId(),goodsId); if(order!=null) {//重复下单 model.addAttribute("errorMessage", CodeMsg.REPEATE_MIAOSHA); return "miaosha_fail"; } //可以秒杀,原子操作:1.库存减1,2.下订单,3.写入秒杀订单--->是一个事务 OrderInfo orderinfo=miaoshaService.miaosha(user,goodsvo); //如果秒杀成功,直接跳转到订单详情页上去。 model.addAttribute("orderinfo", orderinfo); model.addAttribute("goods", goodsvo); return "order_detail";//返回页面login } }
秒杀业务主要逻辑:
- 判断登录
- 根据商品id从数据库拿到商品
- 判断库存,库存足够,进行秒杀,不足则结束
- 判断是否重复秒杀(我们限制一个用户只能秒杀一件商品,怎么判断?即从数据库根据商品和用户id 查询秒杀订单表,如果已经存在订单,说明重复秒杀 ,给出提示,退出)
- 以上都通过,那么该用户可以秒杀商品
注意:
执行秒杀逻辑是一个原子操作,是一个事务:
- 库存减1
- 下订单(写入秒杀订单)
所以使用@Transactional注解标注,其中一步没有成功,则回滚
MiaoshaService 代码:
[code] @Service public class MiaoshaService { @Autowired GoodsService goodsService; @Autowired OrderService orderService; /** * 秒杀,原子操作:1.库存减1,2.下订单,3.写入秒杀订单--->是一个事务 * 返回生成的订单 * @param user * @param goodsvo * @return */ @Transactional public OrderInfo miaosha(MiaoshaUser user, GoodsVo goodsvo) { //1.减少库存,即更新库存 goodsService.reduceStock(goodsvo);//考虑减少库存失败的时候,不进行写入订单 //2.下订单,其中有两个订单: order_info miaosha_order OrderInfo orderinfo=orderService.createOrder(user,goodsvo); return orderinfo; } }
注意:执行秒杀事务的时候,先生成详细订单,然后生成秒杀订单,为了进一步确保秒杀过程中一个用户只能秒杀一件商品,我们给秒杀订单表miaosha_order表添加一个唯一索引,如果再次插入相同的id与goodsId相同的字段,那么将不会被允许,从而在事务中插入失败而回退。
秒杀订单表miaosha_order:
为秒杀订单表添加唯一索引:
OrderService 代码:
[code] @Service public class OrderService { @Autowired OrderDao orderDao; /** * 代码1.0 * 根据用户userId和goodsId判断是否有者条订单记录,有则返回此纪录 * @param id * @param goodsId * @return */ public MiaoshaOrder getMiaoshaOrderByUserIdAndGoodsId(Long userId, Long goodsId) { return orderDao.getMiaoshaOrderByUserIdAndGoodsId(userId,goodsId); } /** * 生成订单,事务 * @param user * @param goodsvo * @return */ @Transactional public OrderInfo createOrder(MiaoshaUser user, GoodsVo goodsvo) { //1.生成order_info OrderInfo orderInfo=new OrderInfo(); orderInfo.setDeliveryAddrId(0L);//long类型 private Long deliveryAddrId; L orderInfo.setCreateDate(new Date()); orderInfo.setGoodsCount(1); orderInfo.setGoodsId(goodsvo.getId()); //秒杀价格 orderInfo.setGoodsPrice(goodsvo.getMiaoshaPrice()); orderInfo.setOrderChannel(1); //订单状态 ---0-新建未支付 1-已支付 2-已发货 3-已收货 orderInfo.setOrderStatus(0); //用户id orderInfo.setUserId(user.getId()); //返回orderId //long orderId= orderDao.insert(orderInfo); //2.生成miaosha_order MiaoshaOrder miaoshaorder =new MiaoshaOrder(); miaoshaorder.setGoodsId(goodsvo.getId()); //将订单id传给秒杀订单里面的订单orderid miaoshaorder.setOrderId(orderInfo.getId()); miaoshaorder.setUserId(user.getId()); orderDao.insertMiaoshaOrder(miaoshaorder); return orderInfo; } public OrderInfo getOrderByOrderId(long orderId) { return orderDao.getOrderByOrderId(orderId); } }
OrderDao代码:
[code]@Mapper public interface OrderDao { @Select("select * from miaosha_order where user_id=#{userId} and goods_id=#{goodsId}") public MiaoshaOrder getMiaoshaOrderByUserIdAndGoodsId(@Param("userId")Long userId, @Param("goodsId")Long goodsId); @Insert("insert into order_info (user_id,goods_id,goods_name,goods_count,goods_price,order_channel,order_status,create_date) values " + "(#{userId},#{goodsId},#{goodsName},#{goodsCount},#{goodsPrice},#{orderChannel},#{orderStatus},#{createDate})") @SelectKey(keyColumn="id",keyProperty="id",resultType=long.class,before=false,statement="select last_insert_id()") public long insert(OrderInfo orderInfo);//使用注解获取返回值,返回上一次插入的id @Select("select * from order_info where user_id=#{userId} and goods_id=#{goodsId}") public OrderInfo selectorderInfo(@Param("userId")Long userId, @Param("goodsId")Long goodsId);//使用注解获取返回值,返回上一次插入的id @Insert("insert into miaosha_order (user_id,goods_id,order_id) values (#{userId},#{goodsId},#{orderId})") public void insertMiaoshaOrder(MiaoshaOrder miaoshaorder); @Select("select * from order_info where id=#{orderId}") public OrderInfo getOrderByOrderId(@Param("orderId")long orderId); }
相关文章推荐
- 【SpringBoot商城秒杀系统项目实战13】秒杀商品详情页+秒杀倒计时功能实现
- 基于SpringMVC+Spring+MyBatis实现秒杀系统【业务逻辑】
- 【SpringBoot商城秒杀系统项目实战03】集成Thymeleaf做页面模板
- 【SpringBoot商城秒杀系统项目实战04】集成Mybatis与druid
- 【SpringBoot商城秒杀系统项目实战07】通用缓存Key的设计与封装
- 基于SpringBoot实现高并发商品秒杀系统
- 【SpringBoot商城秒杀系统项目实战08】两次MD5加密设计
- 【SpringBoot商城秒杀系统项目实战24】安全优化 接口限流防刷
- Spring Boot+Spring Security 实现自动登录功能(实战+源码分析)
- Spring Boot 会员管理系统之处理文件上传功能
- 【SpringBoot商城秒杀系统项目实战16】使用JMeter压测秒杀系统
- 【SpringBoot】DEMO:实战①——注册功能实现
- 最新基于SpringBoot Java商城秒杀系统的设计与实战
- SpringBoot秒杀系统实战19-秒杀静态化+订单详情静态化
- SpringBoot秒杀系统实战21-高并发秒杀系统接口优化 RabbitMQ异步下单...
- 一步一步实现web程序信息管理系统之三----登陆业务逻辑实现(验证码功能+参数获取)
- Springboot + rabbitMQ实现延迟消费以及spring与策略模式联合处理不同的业务(一)
- 【SpringBoot商城秒杀系统项目实战02】优雅代码编写之封装json输出
- 【SpringBoot商城秒杀系统项目实战20】高并发秒杀接口优化
- 【SpringBoot商城秒杀系统项目实战12】商品列表页