当前位置: 首页 > news >正文

多终端网站dw做的网站如何使用

多终端网站,dw做的网站如何使用,无锡网站制作方案,宁波seo企业网络推广优惠券秒杀一人一单 前言一、需求以及之前存在的问题二、增加一人一单逻辑1.初步代码2.封装一人一单逻辑3.控制锁的粒度 三、事务控制问题四、总结 前言 跟随黑马虎哥学习redis: 这是我认为b站上最好的redis教程,各方面讲解透彻,知识点覆盖…

优惠券秒杀一人一单

  • 前言
  • 一、需求以及之前存在的问题
  • 二、增加一人一单逻辑
    • 1.初步代码
    • 2.封装一人一单逻辑
    • 3.控制锁的粒度
  • 三、事务控制问题
  • 四、总结


前言

跟随黑马虎哥学习redis:

这是我认为b站上最好的redis教程,各方面讲解透彻,知识点覆盖比较全。
黑马redis视频链接:B站黑马redis教学视频
本文参考黑马redis课程笔记


一、需求以及之前存在的问题

需求:修改秒杀业务,要求同一个优惠券,一个用户只能下一单。

之前的问题:
优惠卷是为了引流,但是目前的情况是,一个人可以无限制的抢这个优惠卷,所以我们应当增加一层逻辑,让一个用户只能下一个单,而不是让一个用户下多个单。

具体操作逻辑如下:比如时间是否充足,如果时间充足,则进一步判断库存是否足够,然后再根据优惠卷id和用户id查询是否已经下过这个订单,如果下过这个订单,则不再下单,否则进行下单。

二、增加一人一单逻辑

实现流程:
在这里插入图片描述

1.初步代码

@Override
public Result seckillVoucher(Long voucherId) {// 1.查询优惠券SeckillVoucher voucher = seckillVoucherService.getById(voucherId);// 2.判断秒杀是否开始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {// 尚未开始return Result.fail("秒杀尚未开始!");}// 3.判断秒杀是否已经结束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {// 尚未开始return Result.fail("秒杀已经结束!");}// 4.判断库存是否充足if (voucher.getStock() < 1) {// 库存不足return Result.fail("库存不足!");}// 5.一人一单逻辑// 5.1.用户idLong userId = UserHolder.getUser().getId();int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();// 5.2.判断是否存在if (count > 0) {// 用户已经购买过了return Result.fail("用户已经购买过一次!");}//6,扣减库存boolean success = seckillVoucherService.update().setSql("stock= stock -1").eq("voucher_id", voucherId).update();if (!success) {//扣减库存return Result.fail("库存不足!");}//7.创建订单VoucherOrder voucherOrder = new VoucherOrder();// 7.1.订单idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);voucherOrder.setUserId(userId);// 7.3.代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);return Result.ok(orderId);}

存在问题:
现在的问题还是和之前一样,并发过来,查询数据库,都不存在订单,所以我们还是需要加锁,但是乐观锁比较适合更新数据,而现在是插入数据,所以我们需要使用悲观锁操作

注意:
在这里提到了非常多的问题,我们需要慢慢的来思考,首先我们的初始方案是封装了一个createVoucherOrder方法,同时为了确保他线程安全,在方法上添加了一把synchronized

2.封装一人一单逻辑

@Transactional
public synchronized Result createVoucherOrder(Long voucherId) {Long userId = UserHolder.getUser().getId();// 5.1.查询订单int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();// 5.2.判断是否存在if (count > 0) {// 用户已经购买过了return Result.fail("用户已经购买过一次!");}// 6.扣减库存boolean success = seckillVoucherService.update().setSql("stock = stock - 1") // set stock = stock - 1.eq("voucher_id", voucherId).gt("stock", 0) // where id = ? and stock > 0.update();if (!success) {// 扣减失败return Result.fail("库存不足!");}// 7.创建订单VoucherOrder voucherOrder = new VoucherOrder();// 7.1.订单idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 7.2.用户idvoucherOrder.setUserId(userId);// 7.3.代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 7.返回订单idreturn Result.ok(orderId);
}

此时面临的问题:
这样添加锁,锁的粒度太粗了,在使用锁过程中,控制锁粒度 是一个非常重要的事情,因为如果锁的粒度太大,会导致每个线程进来都会锁住

3.控制锁的粒度

intern() 这个方法是从常量池中拿到数据,如果我们直接使用userId.toString() 他拿到的对象实际上是不同的对象,new出来的对象,我们使用锁必须保证锁必须是同一把,所以我们需要使用intern()方法

@Transactional
public  Result createVoucherOrder(Long voucherId) {Long userId = UserHolder.getUser().getId();synchronized(userId.toString().intern()){// 5.1.查询订单int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();// 5.2.判断是否存在if (count > 0) {// 用户已经购买过了return Result.fail("用户已经购买过一次!");}// 6.扣减库存boolean success = seckillVoucherService.update().setSql("stock = stock - 1") // set stock = stock - 1.eq("voucher_id", voucherId).gt("stock", 0) // where id = ? and stock > 0.update();if (!success) {// 扣减失败return Result.fail("库存不足!");}// 7.创建订单VoucherOrder voucherOrder = new VoucherOrder();// 7.1.订单idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);// 7.2.用户idvoucherOrder.setUserId(userId);// 7.3.代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 7.返回订单idreturn Result.ok(orderId);}
}

三、事务控制问题

以上代码还是存在问题,问题的原因在于当前方法被spring的事务控制,如果你在方法内部加锁,可能会导致当前方法事务还没有提交,但是锁已经释放也会导致问题,所以我们选择将当前方法整体包裹起来,确保事务不会出现问题:

在这里插入图片描述

但是以上做法依然有问题,因为你调用的方法,其实是this.的方式调用的,事务想要生效,还得利用代理来生效,所以这个地方,我们需要获得原始的事务对象, 来操作事务

Long userId = UserHolder.getUser().getId();//创建锁对象SimpleRedisLock simpleRedisLock = new SimpleRedisLock("order" + userId, stringRedisTemplate);//获取锁boolean isLock = simpleRedisLock.tryLock(1200);if (!isLock) {//获取锁失败,返回错误信息或重试return Result.fail("不允许重复下单");}try {//增加代理对象进行事务的控制IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}finally {simpleRedisLock.unlock();}

四、总结

这只是一人一单单机实现的方法,因为synchronized锁只能确保在一个jvm中实现锁的互斥,如果在集群中,有多个jvm,那就不能实现互斥锁,最终还是会导致并发问题,这个问题的解决由集群中的分布式锁解决。
在这里插入图片描述

http://www.yayakq.cn/news/261935/

相关文章:

  • asp.net怎么生成网站门户网站系统建设项目投标书
  • 免费 网站 手机高端网站设计地址
  • 做网站的服务器很卡怎么办旅游网站建设前期分析
  • 建个网站需要投资多少济南网站制作公司哪家好
  • 手机网站宽度展示网站多少钱一个
  • 在线A视频网站(级做爰片)wordpress 微信接口
  • 网站动态图片制作珠海seo推广
  • 淘宝可以在哪些网站上面打做推广自建网站的劣势
  • 武陵天下网站开发长江证券官方网站下载
  • 西安网站制作顶开发一个网站需要哪些步骤
  • 双色调网站西安百姓网免费发布信息网
  • python做网站稳定吗seo网络推广员招聘
  • 通州建设网站wordpress区域编辑器
  • jsp网站开发介绍电子商务网站推广怎么做
  • 医院网站php源码做网站赚钱还是企业宣传片
  • 企业网站标签页是什么贵州两学一做教育网站
  • 沧州网站网站建设北京网站建设seo公司哪家好
  • 波兰网站后缀网站备案地点
  • 免费网站入口设计制作的基本步骤是哪四个
  • 义乌企业网站设计2核4g 1m做网站
  • 手机社交网站建设不同性质网站的营销特点一览表
  • sharepoint做网站拓客软件哪个好用
  • 做网站的属于什么专业?个人网页设计下载
  • 为什么网站生成后不显示flash如何制作网站
  • seo如何优化网站推广网站建设一般多少钱网址
  • 铁道部售票网站多少钱建设asp.net网站开发与项目实战
  • 网站架构设计面试技巧手机app快速开发平台
  • 什么是单页网站网站模板种类
  • 济南优化网站wordpress 角色管理
  • 网站网页建设艺术类考生有哪些专业