已经开始

秒杀结束

秒杀倒计时

所以我们去秒杀第一个商品:

在之前的goods_detail.html里面的秒杀按钮点击之后提交/miaosha/do_miaosha,以POST类型提交,带有数据是秒杀商品的goodsId

新建一个MiaoshaController,定义接收该秒杀请求的接口方法doMiaosha

我们秒杀成功之后,那么会直接进入订单的详情页,所以我们秒杀成功后直接返回订单信息,并且返回值订单页面。

MiaoshaController代码

@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 代码:

@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 代码:

@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代码:

@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);

}

java秒杀功能的实现_【IDEA+SpringBoot+Java商城秒杀实战14】秒杀功能的实现(秒杀业务逻辑处理)...相关推荐

  1. java正则截取xml节点_实例讲述Java使用正则表达式截取重复出现的XML字符串功能...

    Java使用正则表达式截取重复出现的XML字符串功能示例 本文实例讲述了Java使用正则表达式截取重复出现的XML字符串功能.分享给大家供大家参考,具体如下: public static void m ...

  2. Java多线程读取excel文件_解决springboot 多线程使用MultipartFile读取excel文件内容报错问题...

    springboot项目开启多线程 启动类加注解开启 @EnableAsync,实现类方法加注解 @Async 前端页面 报错信息 java.io.FileNotFoundException: C:\ ...

  3. java 获取 反射 方法 名_乐字节Java反射之一:反射概念与获取反射源头Class

    一.Java反射机制概念 "程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言",如Python, Ruby是动态语言:显然C++,Java,C#不是动态语言,但是JAV ...

  4. 深入java虚拟机 第四版_深入理解Java虚拟机-常用vm参数分析

    Java虚拟机深入理解系列全部文章更新中... https://blog.ouyangsihai.cn/shen-ru-li-jie-java-xu-ni-ji-java-nei-cun-qu-yu- ...

  5. java工程师有什么要求_什么是java,java工程师应该具备哪些能力?

    这两年,虽然各种各样的新兴语言不断涌现,收获了一大批迷粉,但是java的地位,却始终难以撼动.作为一门成熟的,经久不衰的语言,java吸引了越来越多的人,想加入进来.但是,很多人在选择java前,或多 ...

  6. java char字符转编码_一、java基础-数据类型_数据类型转化_字符编码_转义字符

    1.Java  支持的8种基本数据类型: java的四种整数数据类型:byte 1    short 2     int4     long8 byte     8位带符号整数 -128到127之间的 ...

  7. java的应用程序开发_开发一个Java应用程序(1)

    开发一个Java应用程序(1) App Engine上的Java Web应用程序通过Java Servlet标准接口与应用程序服务器交互.一个应用程序由一个或多个类组成,这些类都扩展自一个servle ...

  8. java带参数的构造方法_看了Java的Class的源码,我自闭了

    作者丨chenweicool 来源:https://www.cnblogs.com/chentang/p/13170081.html 1.class这个类是什么 Class的本质也是一个类,只不过它是 ...

  9. java中注解的解析_全面解析Java中的注解与注释

    注解一.什么是 Annotation? (注解 or 注释)Annotation, 准确的翻译应该是 -- 注解. 和注释的作用完全不一样. Annotation 是JDK5.0及以后版本引入的一个特 ...

  10. java 线程中创建线程_如何在Java 8中创建线程安全的ConcurrentHashSet?

    java 线程中创建线程 在JDK 8之前,还没有办法在Java中创建大型的线程安全的ConcurrentHashSet. java.util.concurrent包甚至没有一个名为Concurren ...

最新文章

  1. 专题 16 基于UDP的通信程序设计
  2. 计算机科学概论ppt免费,计算机科学概论(第9版)Lecture_slide07.ppt
  3. java的两种运行机制_Java☞JVM工作原理
  4. 基于迭代次数和分类准确率的两种排序
  5. 决策树和随机森林(下)
  6. 2018蓝桥杯省赛---java---A---10(付账问题)
  7. bic,orr——设置某些位为0或者1
  8. centos网络隔一段时间就断_如果是中专学历,以后做网络工程师会有瓶颈吗?
  9. Python提取docx文档中例题、插图、表格清单
  10. C语言 底层IO openclose
  11. 云计算开源软件有哪些?
  12. SQLSERVER 创建ODBC 报错的解决办法 SQLState:‘01000‘的解决方案
  13. Python strftime()
  14. eclipse中文版eclipse汉化教程
  15. Openxml 笔记
  16. js中更改div的背景颜色:
  17. python eof是什么_EOF错误python
  18. 计算机类qq网名,最帅的qq名字
  19. VR头显设备相关接口详解
  20. 2020-05-19

热门文章

  1. JS获取当前时间 或时间戳 年月日 时分秒
  2. Python源文件一行字符过长造成的问题
  3. 7.试用期工作总结七
  4. 2022-9-9前段JQuser知识
  5. 误码性能测试基础知识
  6. MPU9250加速度数据
  7. r语言dataellipse_几行R语言代码搞定菌群与环境因子或临床指标相关性的可视化...
  8. 历届JOLT图书奖整理
  9. 获晨晖资本领投的1.5亿元A轮融资,犀思云想为企业用户提供NAAS服务
  10. svn: Working copy 'D:\workspace\mm\WebRoot...'locked; try performing 'cleanup'