本文为原创文章,转载希望注明出处。

抢购业务数据库需要考虑的点如下:

一、超卖现象

场景如下:

库存数是5。现在3个用户来购买,a用户购买2个,b用户购买3个,c用户购买1个。合起来就是准备购买6个。

如果三个用户是同时并发购买,会出现怎样的情况呢?

每个用户进行减库存的时候,语句类似于:

update goods set amount=amount-购买数量 where goods_id=xxx。

mysql会锁定这一行数据(使用innodb存储引擎),数据库加的是排他锁。根据排他锁的特点:其他线程不能读、不能写此行数据。

排他锁情况下,那么其他用户就是等待状态了。

1、A用户执行update的时候,锁定库存数据。update执行完毕后,减去了2个后,mysql自动释放锁。

2、b用户执行,减去了3个。此时,已经卖掉5个库存了。库存数为0了。

3、但是c用户接着执行,Update goods set amount=amount-1 where goods_id=xxx

结果库存数量变成-1了。

思考:把库存数量字段的类型,设计成正数类型,不允许出现负数,会怎么样呢?

测验结果:数据库会直接报错。通不过。

解决办法:只有库存数量,大于或等于购买数量的时候,才能去减库存。其他情况,提示信息,库存不足。

sql语句如下:

update goods set amount=amount-购买数量 where goods_id=xxx AND amount>=购买数量

这样,轮到c执行的时候,由于使用了amount>=购买数量做限制条件,update语句返回的受影响的行数是0,意味着执行失败了。直接提示,库存不足。

二、并发抢购造成的速度慢问题

1、实现方式对比:悲观锁与乐观锁

第一种问题中描述的超卖现象,其实是并发抢购时出现的情况。用到的是数据库内带的加排他锁方式,阻止了其他线程读取、访问数据,这要等待操作完毕后其他线程才能操作,这种方式是悲观锁方式。这样会等待下去。

使用数据库的悲观锁,是避免了数据并发更新,但是,加锁毕竟是很耗服务器资源的,用户要等待下去。所以并不能达到好的性能和高并发。

业界使用乐观锁的办法来解决:使用数据库的乐观锁是通用解决办法。通用锁实现了版本控制。不会进行排斥掉。减少资源的消耗。

乐观锁是相对悲观锁而言的,使用的是更加宽松的锁定方式。

乐观锁,通俗说就是:修改数据的时候,不给数据加锁。

既然不加锁,其他线程也是可以访问、修改数据。但是,修改的时候会获取一个版本号,只有版本号符合了,才算更新成功。

不成功的,都算抢购失败。

2、乐观锁的具体实现方式

乐观锁的机制与代码版本库svn很相似,这种方式,叫做多版本记录方式。

如果在我提交代码之前用本地代码的版本号与服务器做对比,如果本地版本号小于服务器上最新版本号,则提交失败,产生冲突代码,让用户决定选择哪个版本继续使用。

逻辑描述:

if(之前读取到行的版本号+1=数据库此行现在的版本号+1){

//符合预期,数据库的数据没有给其他用户修改掉。可以直接写入数据了

}else{

//数据已经被修改了。所以当前的版本已经落后了。不能进行更新

}

例子:

给表goods加一个版本字段version,用来记录行数据值的版本号。

版本号version字段,设计成一个正整数,比如是时间戳。每次修改后,要将version字段的值加1:  1496916794、1496916795、1496916796、1496916797、1496916798.................

读数据的时候,顺便将版本号的值读取出来。update时,做版本号对比,如下:

1、先读取这个商品的信息,顺便将版本号读取出来

select amount,version from t_goods where goods_id=8899;

2、更新数据

update goods

set amount=amount-2,version=version+1

where goods_id=8899 and version=#{version} and amount>=2;

sql解释:

#{version}是之前select读取到的版本号,填入进去,意思是只能修改这样的。

修改的时候,限制条件-必须版本号等于原来的版本号才能去修改。否则不能修改。更新成功的同时,版本号要加1。

优点:使用数据库的乐观锁是通用解决办法。通用锁实现了版本控制。线程之间同时操作,不加锁,线程不用等待了。减少了数据库资源的消耗。

缺点:会增加cpu的计算开销。不过值得这样做,由于没有加锁进行阻塞,用户不用等待结果,很快能等到执行结果了,用户体验更好。抢购的并发数其实提高了。

三、减库存和下单保持在一个事务内

如果不在一个事务内,可能出现两种现象:

1、订单入库失败、减库存成功。发现订单入库失败,减库存就不要继续进行下去了。

2、订单入库成功、减库存失败。实际下了20个订单,库存却没有减。数据不一致了。

四、虚拟库存和真实库存两套方案

考虑几种情况:

1、有些人下单完后,最终并不会去付款。如果一下单就马上减库存,很多人下单,最终并不会去付款,可能导致库存数最后为0,别的用户无法下单了。而实际中仓库中却有库存在,这样库存数据是不准确的。

2、什么时候减库存? 是下单完成减库存、还是付款完后减库存呢?

付款后,才减库存,可能出现的现象:用户下完单,接着去付款,结果库存不够了。这样用户体验很不好。

下完单就减库存,能够保证用户下单只要付款,就一定能买到这个商品。用户体验较好。

针对一些人下单后,不付款,占着库存资源,其他人无法下单。这个问题好解决,给付款设置一个有效期限,比如30分钟。超过这个时间,库存就释放掉了。

具体技术实现办法:下单后,马上减去库存。另外设置一个定时脚本,扫描超过30分未支付的订单,把订单中的商品数量返回到库存中去。

为什么使用虚拟库存和真实库存两套方案?

假设库存数是50,a订单购买了5个件商品,支付完毕,库存数减去5,库存数变成了45件。由于还没有发货,实际库存中还有50件商品。这样会出现混淆了。

使用两套库存记录方案是有必要的!

下单-操作虚拟库存数

商品发货出库-操作真实库存数

真实库存数,记录下仓库中这件商品真有多少件。真实库存,其实非常方便内部人员查看,它只有商品出库,这个库存才减。

虚拟库存,用来应对商品购买的。表明,还有多少数量可以给用户去购买。并不表示仓库中的库存数。

五、频繁读库存的压力

因为,每次点击,都要读取库存,判断:有没有库存。如果读库存走的是数据库判断,很多人来抢购的情况下,数据库的压力会很大。

假设是1万个用户同时访问抢购页面。数据库接受的访问次数是1万个并发。

用户还要进行刷新页面操作,由于每次刷新都会走数据库判断库存。数量会更大。数据库的压力就更大了。

所以最好是,把库存总数,缓存在redis中去。

内存中缓存的库存数量,只用来做读判断。这样压力扛住了。而更改数据库的库存总数了,程序马上要把库存总数,同步到缓存中去。

系统抗压力问题

一、如何限流

二、如何防止恶意刷数据。

防止的就是写代码去频繁请求,为了识别是机器还是人工。加友好一点的验证码。

mysql秒杀业务瓶颈_抢购(秒杀)业务的技术要点相关推荐

  1. mysql i o瓶颈_性能瓶颈--DISK(I/O)

    说到磁盘,这是数据持久化保存的一种保存媒介,也是计算机必不可少的一种硬件设备,而想要用到磁盘就必须提到文件系统. 文件系统 文件系统是构建在磁盘上的,用来管理文件的.为了方便管理,Linux为每个文件 ...

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

    已经开始 秒杀结束 秒杀倒计时 所以我们去秒杀第一个商品: 在之前的goods_detail.html里面的秒杀按钮点击之后提交/miaosha/do_miaosha,以POST类型提交,带有数据是秒 ...

  3. JSD-2204-(业务逻辑开发)-秒杀业务-酷鲨商城前台业务总结-Day16

    1.开发酷鲨秒杀业务 1.1创建流控和降级的处理类 秒杀业务肯定是一个高并发的处理,并发数超过程序设计的限制时,就需要对请求的数量进行限流 Sentinel是阿里提供的SpringCloud组件,主要 ...

  4. java redis实现抢购_【抢购/秒杀】redis实现高并发下的抢购/秒杀功能

    问题: 抢购/秒杀是如今很常见的一个应用场景,那么高并发竞争下如何解决超抢(或超卖库存不足为负数的问题)呢? 常规写法: 查询出对应商品的库存,看是否大于0,然后执行生成订单等操作,但是在判断库存是否 ...

  5. rust大量科技零件_并完美解决了业务瓶颈,Rust不是垃圾收集的语言

    概述 案例涉及的是一个企业的业务监控,该用来以帮助人员监控业务API.当客户的应用程序调用API时,会向发送日志,对发送的日志中进行监控和分析. 数据流为平均每分钟处理30k 的API调用.每个客户都 ...

  6. mysql查询单一分行客户情况_数据库--单业务场景的客户需求

    记录一些对数据库的理解,如下: 数据库,其实就是存数据的仓库,就像冰箱是存食物的一样,有了它之后,我们就可以在系统上对数据进行增删改查,比如我们要查看自己余额宝里面的钱,查每天的收益,这些数据都是系统 ...

  7. 限时抢购秒杀系统架构分析与实战

    1 秒杀业务分析 正常电子商务流程 (1)查询商品:(2)创建订单:(3)扣减库存:(4)更新订单:(5)付款:(6)卖家发货 秒杀业务的特性 (1)低廉价格:(2)大幅推广:(3)瞬时售空:(4)一 ...

  8. java秒杀架构设计_秒杀系统设计架构与实现

    最近https://blog.csdn.net/qq_27631217/article/details/80657271做了一个点餐的平台,其中涉及到一个很重要的问题,活动期间的秒杀系统的实现. 抢购 ...

  9. 秒杀微服务实现抢购代金券功能

    文章目录 需求分析 秒杀场景的解决方案 数据库表设计 代金券表 抢购活动表 订单表 创建秒杀服务 pom依赖 配置文件 关系型数据库实现代金券秒杀 相关实体引入 抢购代金券活动信息 代金券订单信息 R ...

最新文章

  1. linux cuda 异常退出,cudaErrorCudartUnloading问题排查及建议方案
  2. 霍金家人声明:他的成功将继续存在 我们永远怀念他
  3. [基础]Javascript中的继承示例代码
  4. lisp 图元 天正 自定义_C# 自定义autolisp 函数 研究
  5. python结束程序再重新执行_Python对象对重新执行程序的持久性
  6. Navicat安装(图文教程)
  7. 数字听力Numbers Listening
  8. Atmega16驱动三轴加速度传感器MMA7455
  9. S-LIME阅读笔记(有实验代码)
  10. JavaEE-常用API(String、ArrayLis)
  11. Python计算机视觉-仿射扭曲简单实例
  12. flutter 中Sliver一些想法
  13. 2022年广东国家级专精特新企业奖励及培育方法,补贴50-100万
  14. 聚合型代码审计工具QingScan使用实践
  15. elasticjob-配置手册
  16. mysql 把表名改成大写_mysql 把表名自动改为大写
  17. c语言解除宏定义_3.3.5 取消宏定义和重新定义宏
  18. 电脑病毒怎么彻底清理?你不知道的8个方法
  19. LBG算法、Lloyd算法和K均值算法
  20. 硬核!用Arduino打造纯机械装置模拟数字时钟

热门文章

  1. linux vim 高亮查找,vim搜索高亮关键字怎么取消,vim查询高亮搜索显示如何清除取消...
  2. matlab画三维图像
  3. Problem A:Serval 的俳句
  4. 牛客网训练部队java_训练部队---牛客网第三场校招模拟
  5. idea中json转实体类
  6. java生成.h头文件_javah头文件生成器
  7. byte 类型数组如何定义如何的赋值
  8. 两个byte数组拼接_java中两个byte数组实现合并的示例
  9. utf8mb4 占用字节_如果我的MP3占用不到700MB的空间,为什么只能将80分钟的音乐刻录到CD?...
  10. 企业租用服务器大带宽有哪些优势