京东二面:商品库存的扣除过程,如何防止超卖?

点击上方蓝色“后端面试那些事儿”,选择“设为星标”

学最好的别人,做最好的自己

作者:iloveoverfly

来源:blog.csdn.net/new_com/article

/details/105568124

在商品购买的过程中,库存的抵扣过程,一般操作如下:

  1. select根据商品id查询商品的库存。
  2. 根据下单的数量,计算库存是否足够,如果存库不足则抛出库存不足的异常,如果库存足够,则减去扣除的库存得到最新的库存剩余值。
  3. set设置最新的库存剩余值。

上述过程的伪代码如下:

// 根据商品id获取商品剩余库存

# 并发修改数据库存超卖

如果数据库事务的隔离级别不是串行化(serializable),根据事务的特性,在并发修改的时候,可能会出现写覆盖的问题。

假设,商品的剩余库存stock_remaing 为100,客户A下单20,客户B下单30,在并发扣库存的时候,可能存在超卖。如果客户A和客户B同时获取剩余库存为100,则会出现事务后提交的值会覆盖前一个客户提交的值,有可能剩余的库存是80或者70。流程如下:

图片

# 加锁更新存库

为了在事务控制中,防止写覆盖,你会想到使用select for update的方式,将该商品的库存锁住,然后执行余下的操作。

流程如下:

图片

以上,使用悲观锁方式,在分布式服务中,如果并发情况比较高的时候,扣减库存的操作是串行操作,效率很低。

# 使用乐观锁的方式更新

在更新的时候,使用(CAS+版本号更新)+重试条件(重试次数或者重试时间限制)乐观锁的方式更新库存。此时,如果,客户A和客户B同时读取到库存剩余100,在更新的时候,有一个操作会失败。流程如下:

图片

该种方式可以大大提高并发性,也可以保证数据的一致性;通过重试次数和重试时间的条件控制,可以防止过多的重试带来的数据库压力。

# 可以使用直接递减的方式执行么?

在抵扣库存的时候,有的人提议不执行select,计算,set三段式的操作,直接扣减的方式,并且对于扣减到小于零的情况作了判断。伪代码如下:

update stock_table set remaing_stock=remaing_stock-${quantity} 

在分布式服务调用中,因为网络异常,获取服务器异常,可能在微服务调用时,存在服务重试。例如,场景的网关超时,服务重试机制。此时,该种方式不满足幂等性,而存在多扣的情况。例如,同一用户扣减库存时,服务重试,极端情况下,该用户扣减库存操作执行多次,则就出现了商品超卖。

# 可以使用redis进行库存的抵扣么?

由于没有研究过redis源码,对于这种方式参考了大牛的回复,答案是可以使用redis的事务性扣减余额,但在CAS机制上比mysql没有优势,高性能是因为其内存存储的原因,带来的副作用是数据有丢失风险。

图片

往期推荐

[

面试官:private修饰的方法可以通过反射访问,那么private的意义是什么?

](https://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247500286&idx=1&sn=84d8c65db7cdff455c4376fd2c775e29&chksm=97b45fe6a0c3d6f066fd2e642d4f9944db9f1f5c64e749d53df54132acb2c6b7c7b2ab6fa071&scene=21#wechat_redirect)

[

Linux 环境变量配置汇总

](https://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247500286&idx=2&sn=d04b00c1a58f130778e03f42b88d2587&chksm=97b45fe6a0c3d6f03e8fe13c8cbda57b46201acd5468e0650a4c266a1ebbaca66b3e0677e4f0&scene=21#wechat_redirect)

[

《Java 编程思想》最新中文版开源,免费领取

](https://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247500286&idx=3&sn=cc30320735c29d3f514dff4e07514dd2&chksm=97b45fe6a0c3d6f098ed0fd2a9556c33b019bcdd8acf426e770892a66971574a4968409fc8dd&scene=21#wechat_redirect)

[

还在用策略模式解决 if-else?Map+函数式接口方法才是YYDS!

](https://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247500206&idx=1&sn=6f050b84b0e790cb2b06cf579957689e&chksm=97b45fb6a0c3d6a06942c518108ba6ed275448fb89631ada7ff25d273573f8b340d89163d6a1&scene=21#wechat_redirect)

[

使用雪花id或uuid作为Mysql主键,被老板怼了一顿!

](https://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247500206&idx=2&sn=841bfc417f49692dd09980a6f2a527eb&chksm=97b45fb6a0c3d6a02eb76b4c863e2bc37b56e465289f166ae0169d33d8493141c612dcaccc6a&scene=21#wechat_redirect)

[

在项目中用了Arrays.asList、ArrayList的subList,被公开批评

](https://mp.weixin.qq.com/s?__biz=MzIxMzQzNzMwMw==&mid=2247500168&idx=1&sn=a8c8fc7d1ba89d66ba213a66dd735415&chksm=97b45f90a0c3d6868461d6ee0d30d826e9d5d8711139cfbca9507f04f07b08fbc77c646cafe6&scene=21#wechat_redirect)

一起进大厂,每日学干货

关注我回复【加群】,加入Java技术交流群

图片

后端面试那些事

专注分享后端干货!面向大厂,一起进步!

5篇原创内容

公众号

图片

点击“阅读原文”,领取 2021 年最新免费技术资料大全

↓↓↓


原网址: 访问
创建于: 2022-02-10 14:09:42
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论