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

Redis优惠券秒杀超卖问题

Redis秒杀超卖问题

  • 前言
  • 一、出现秒杀超卖的原因
  • 二、超卖解决方案
    • 使用乐观锁解决超卖问题
    • 程序中进行解决


前言

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


一、出现秒杀超卖的原因

超卖问题分析:
在我们原有代码中是这么写的

 if (voucher.getStock() < 1) {// 库存不足return Result.fail("库存不足!");}//5,扣减库存boolean success = seckillVoucherService.update().setSql("stock= stock -1").eq("voucher_id", voucherId).update();if (!success) {//扣减库存return Result.fail("库存不足!");}

假设线程1过来查询库存,判断出来库存大于1,正准备去扣减库存,但是还没有来得及去扣减,此时线程2过来,线程2也去查询库存,发现这个数量一定也大于1,那么这两个线程都会去扣减库存,最终多个线程相当于一起去扣减库存,此时就会出现库存的超卖问题。

超卖原因流程图:

超卖原因

二、超卖解决方案

超卖问题是典型的多线程安全问题,针对这一问题的常见解决方案就是加锁:而对于加锁,我们通常有两种解决方案:

在这里插入图片描述
由于加入悲观锁,他认为安全问题一定发生,所以一定会获取锁进行串行执行,这样程序的性能跟吞吐量等受到很大的影响,效率大大降低,不到万不得已不使用悲观锁

使用乐观锁解决超卖问题

乐观锁:
会有一个版本号,每次操作数据会对版本号+1,再提交回数据时,会去校验是否比之前的版本大1 ,如果大1 ,则进行操作成功,这套机制的核心逻辑在于,如果在操作过程中,版本号只比原来大1 ,那么就意味着操作过程中没有人对他进行过修改,他的操作就是安全的,如果不大1,则数据被修改过,当然乐观锁还有一些变种的处理方式比如cas

程序中进行解决

我们进行扣减库存时,加入判断:

boolean success = seckillVoucherService.update().setSql("stock= stock -1") //set stock = stock -1.eq("voucher_id", voucherId).eq("stock",voucher.getStock()).update(); //where id = ? and stock = ?

以上逻辑的核心含义是:只要我扣减库存时的库存和之前我查询到的库存是一样的,就意味着没有人在中间修改过库存,那么此时就是安全的,但是以上这种方式通过测试发现会有很多失败的情况,失败的原因在于:在使用乐观锁过程中假设100个线程同时都拿到了100的库存,然后大家一起去进行扣减,但是100个人中只有1个人能扣减成功,其他的人在处理时,他们在扣减时,库存已经被修改过了,所以此时其他线程都会失败.

通俗一点将:
如果100个线程同时开始进行库存的扣减,只有一个线程在拿到100库存,这时他查询得到的是100,我扣减时候的库存是100,它可以完美运行,这时候库存变成99,剩下的99个线程开始扣减时,他们一开始拿到的是库存是100,扣减时发现库存变成了99,所以肯定就不会扣减,这样异常率就会特别高

修改上面的判断条件:
之前的方式要修改前后都保持一致,但是这样我们分析过,成功的概率太低,所以我们的乐观锁需要变一下,改成stock大于0 即可

boolean success = seckillVoucherService.update().setSql("stock= stock -1").eq("voucher_id", voucherId).update().gt("stock",0); //where id = ? and stock > 0
http://www.lryc.cn/news/102329.html

相关文章:

  • 14个最强大的建筑设计AI工具
  • Ueditor 百度强大富文本Springboot 项目集成使用(包含上传文件和上传图片的功能使用)简单易懂,举一反三
  • 【NLP】一个使用PyTorch实现图像分类的迁移学习实例
  • 【wsl-windows子系统】安装、启用、禁用以及同时支持docker-desktop和vmware方案
  • 使用docker部署springboot微服务项目
  • uniapp兼容微信小程序和支付宝小程序遇到的坑
  • LeetCode208.Implement-Trie-Prefix-Tree<实现 Trie (前缀树)>
  • 第1章 JavaScript简史
  • DevOps-GitHub/GitLab
  • redis群集(主从复制)
  • F5 LTM 知识点和实验 5-健康检测
  • ❤️创意网页:能量棒页面 - 可爱版(加载进度条)
  • C语言中的操作符(万字详解)
  • Panda 编译时原子化 CSS-in-JS 框架的跨平台方案
  • 【图论】BFS中的最短路模型
  • Linux Mint 21.2 ISO 镜像开放下载
  • 版本适配好帮手 Android SDK Upgrade Assistant / Android Studio Giraffe新功能
  • kafka权威指南学习以及kafka生产配置
  • 自由行的一些小tips
  • uiautomatorViewer无法获取Android8.0手机屏幕截图的解决方案
  • 使用LangChain构建问答聊天机器人案例实战(三)
  • 在windows上安装minio
  • 22. 数据库的隔离级别和锁机制
  • 【题解】[ABC312E] Tangency of Cuboids(adhoc)
  • k8s服务发现之使用 HostAliases 向 Pod /etc/hosts 文件添加条目
  • python中有哪些比较运算符
  • Python网络编程详解:Socket套接字的使用与开发
  • Appium+python自动化(二十六)- Toast提示(超详解)简介
  • SpringBoot自动装配介绍
  • 1400*D. Candy Box (easy version)(贪心)