作者:废物大师兄
来源:www.cnblogs.com/cjsblog/p/9135118.html

秒杀的场景有很多,比如:抢购、抢票、抢红包等等。总之,就是在极短时间内有大量的请求。

我们都知道,这种系统设计的大方向就是限流,即通过层层过滤,最终只让相对较少的请求进入到核心业务处理层。

这里不谈秒杀设计,不谈使用队列等使请求串行化,就谈下怎么用锁来保证数据正确,就是已经到减库存那一步了,在这一步中如果保证不超卖。

用队列的话,可以是Java自动的队列,也可以用Redis的LPUSH RPOP

重点是扣减库存

我理解,主要的方式是加锁。

加锁有两个层面:一个是程序层面,另一个是数据库层面。

分布式锁

这种场景下应该很少有人用Java自带的锁(比如:synchronized、Lock)吧,因为它们只在同一个JVM内有效,如果你的应用部署了多台的话,应该用分布式锁。

其实,这里加分布式锁就是将多线程请求转成单线程请求,因为每次只有一个线程获得锁并执行,其余都被阻塞了。

这里有一点需要注意,就是当你应用了事务的话可能会存在问题,请看下面的代码

可能有人会这样写,第一眼看起来挺好的,没问题啊,但仔细实践证明是由问题的。

我们知道,mysql默认的事务隔离级别是REPEATABLE-READ

在这种隔离级别下,同一个事务中多次读取,返回的数据是一样的

同时,Spring声明式事务默认的传播特性REQUIRED

Spring声明式事务是Spring AOP最好的例子,Spring是通过AOP代理的方式来实现事务的,也就是说在调用reduceStock()方法的之前就已经开启了事务。另外,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Spring 系列面试题和答案,非常齐全。

那么,在并发情况下可能会存在这样的情况,假设线程T1和T2都执行到这里,于是它们都开启了事务S1和S2,T1先执行,T2后执行,

由于T2执行的时候事务已经创建了,根据隔离级别,这个时候事务S2读取不到S1已提交的数据,于是就会出现T1和T2读取到的值是一样的,即T2读取的是T1更新前的库存数据。

关于这一点,大家可以自己写个代码测试一下,下面是一段参考:

鉴于这种情况呢,可以将库存放到Redis中,我们直接读写Redis,这样可以避免受数据库事务的影响,当然这也会带来新的问题,不再讨论。另外,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Redis 系列面试题和答案,非常齐全。

数据库乐观锁

CAS(compare and swap)比较并交换

在Java中,一个线程想修改某个变量的值,那么第一步是将变量的值从主内存中读取到自己工作内存中,然后修改,最后写回主内存。

这个过程可以归结为:读取——修改——写入,在写回内存的时候可能当前内存中那个值已经发生了变化,这个时候如果继续写则会覆盖别人的数据,只有当内存中的那个值和它修改之前读到的那个值一样,才可以写入。

这个跟数据库是一样的。

Java中通过Unsafe中compareAndSwapObject这样的方法类实现的,它直接调用CPU指令。

数据库中也有CAS,乐观锁就是一种CAS。

经典的乐观锁实现:

数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。

当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。

更新的时候带上版本号,只有当前版本号与更新之前查询时的版本一致,才会更新

ABA问题

这里顺便多提一句,CAS中的ABA问题

假设,原先的值是A,线程-1读取到的值是A,想把它改成D,但是在此期间,有可能其他线程已经多次修改过这个值,只不过最后当线程-1准备将A改成D的时候,它发现恰好还是A,以为没有人改过,其实这时候的A已经不是原来的A了。

也就是说,尽管修改之前做了比较,当然,仍然会出现如下情况:

产生原因

ABA问题导致的原因,是CAS过程中只简单进行了“值”的校验,有些情况下,“值”虽然相同,却已经不是原来的数据了。

优化方向

CAS不能只比对“值”,还必须确保的是原来的数据,才能修改成功。

常见实践

“版本号”的比对,一个数据一个版本,版本变化,即使值相同,也不应该修改成功。

不仅要关注值,还要关注是不是原来的对象

基于“值”的CAS乐观锁,可能导致ABA问题。CAS乐观锁,必须保证修改时的“此数据”就是“彼数据”,应该由“值”比对,优化为“版本号”比对。

参考:

https://www.sohu.com/a/150900817_178889
https://blog.csdn.net/zhjunjun93/article/details/78560700
https://blog.csdn.net/rexct392358928/article/details/52230737

猜你喜欢

1、2019 年 9 月全国程序员工资统计,你是什么水平?

2、如何才能成为优秀的架构师?

3、从零开始搭建创业公司后台技术栈

4、程序员一般可以从什么平台接私活?

5、37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6、滴滴业务中台构建实践,首次曝光

7、不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

8、15张图看懂瞎忙和高效的区别!

并发减库存,怎么保证不超卖?相关推荐

  1. Redis 如何实现库存扣减操作和防止被超卖?

    Redis 如何实现库存扣减操作和防止被超卖? 在日常开发中有很多地方都有类似扣减库存的操作,比如电商系统中的商品库存,抽奖系统中的奖品库存等. 解决方案 使用mysql数据库,使用一个字段来存储库存 ...

  2. Redis 如何实现库存扣减操作和防止被超卖

    在日常开发中有很多地方都有类似扣减库存的操作,比如电商系统中的商品库存,抽奖系统中的奖品库存等.其基本的流程如下: 1 解决方案 使用mysql数据库,使用一个字段来存储库存,每次扣减库存去更新这个字 ...

  3. java 高并发商城库存订单处理,下单减库存,如何解决高并发减库存问题

    下单减库存,如何解决高并发减库存问题 1. 减库存 一般下单减库存的流程大概是这样的: 1.查询商品库存.这里直接查的Redis中的库存. 2.Redis中的库存减1.这里用到的Redis命令是:in ...

  4. 【万级并发】电商库存扣减如何设计?不超卖!

    随着中国消费认知的不断升级,网购走近千家万户,越来越被人们所接受.淘宝.唯品会.考拉.京东.拼多多等逐渐成为我们生活的重要组成部分. 除了常规的购物下单外,这些电商平台还经常搞一些双十一活动,秒杀.大 ...

  5. 事务隔离机制原理分析以及是否可以防止订单超卖

    事务的隔离机制是指: Read Uncommitted(读取未提交内容) Read Committed(读取提交内容) Repeatable Read(可重读) Serializable(可串行化) ...

  6. Redis 如何实现防止超卖和库存扣减操作?

    电商当项目经验已经非常普遍了,不管你是包装的还是真实的,起码要能讲清楚电商中常见的问题,比如库存的操作怎么防止商品被超卖 解决方案 分析 基于数据库单库存 基于数据库多库存 基于redis 基于red ...

  7. php laravel 抢红包防止并发(超卖也是同理)

    方案1: 原理:后台创建红包后,将红包个数存入redis,采用常量键名拼接红包id 作为key,红包个数为value存入redis,然后当用户领取红包的时候,前端肯定传红包id到后端,后端 先加red ...

  8. 高并发超卖问题简要解决方案

    1.传统通过数据库保证不超卖 事务+行锁并不是解决超卖的方案,只是保障数据的统一性.传统通过回滚事务的方式防止某些用户多卖的情况. 采用新建一个防重表+事务的方式防止超卖.同一事务中,采用如 用户ID ...

  9. Redis解决库存超卖问题,大厂直通车

    查询商品信息 (调用商品服务) 计算总价(生成订单详情) 商品服务扣库存(调用商品服务) 订单入库( 生成订单) // 原始的MySQL同步流程 // 判断此代金券是否加入抢购 SeckillVouc ...

  10. 大神TP_运营大神解密“双十一零超卖”电商库存管理系统

    作者 | 松涛(TP公司电商运营大神) 图片 | 商派 shopex 每到大促,什么"三选一"."二选一"又开始了! 以前呢,东哥领导的京东抗起硬撼天猫的大旗, ...

最新文章

  1. [kuangbin带你飞]专题六-生成最小树
  2. 线段检测M-LSD 已开源
  3. Java 虚拟机学习笔记 | 类加载过程和对象的创建流程
  4. Python基础----NumPy
  5. Redis07-对象结构体redisObject
  6. 详细分析 Sonlogger 任意文件上传漏洞 (CVE-2021-27964)
  7. linux Apache2.4安装提示APR not found的解决办法
  8. MapStruct使用指南
  9. 微信小程序使用wxParse解析html代码
  10. 什么是生成式对抗神经网络GAN
  11. 华为手机灵敏度设置_和平精英灵敏度怎么调最稳华为手机?华为二指灵敏度调整设置一览[多图]...
  12. win10解决桌面图标变白
  13. 基于PHP+MySQL的高校实验室预约管理系统
  14. matlab中字符串和变量一起显示输出eval()函数用法
  15. python 斗破苍穹 词云
  16. configure : error : no acceptable C compiler found in $PATH 解决办法
  17. UVALive 7279 Sheldon Numbers (暴力打表)
  18. 揭秘闲鱼赚钱项目的高端玩法
  19. Win 7+Word 2007仿宋和楷体不能正常显示的解决方法
  20. 微信小程序中使用lodash的问题

热门文章

  1. 网易云上线新版容器服务,开放更多Kubernetes功能
  2. Keras网络层之“关于Keras的层(Layer)”
  3. Tomcat配置文件server.xml(转)
  4. TCP Timestamp选项
  5. 解决linux sshd 超时问题
  6. 实现ls -l功能 和目录实现
  7. 适用于苹果Mac的 5 个 SSH 客户端软件
  8. 苹果mac专业的视频转码器:HandBrake
  9. 从键盘上打开 Mac 应用程序的 4 种方法
  10. Ps 初学者教程,如何在照片中创建纹身合成?