乐趣区

关于java:商品库存的扣除过程如何防止超卖

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

1、select 依据商品 id 查问商品的库存。

2、依据下单的数量,计算库存是否足够,如果存库有余则抛出库存有余的异样,如果库存足够,则减去扣除的库存失去最新的库存残余值。

3、set 设置最新的库存残余值。

上述过程的伪代码如下:

// 依据商品 id 获取商品残余库存
select stock_remaing from stock_table where id=${goodsId};

// 操作库存
// 比拟库存
if(stock_remaing <quantity){// 抛出库存有余的异样}
else{
  // 抵扣当前的库存值
  int new_stock=stock_remaing - quantity;
}

// 依据商品 id 设置计算后的库存
update stock_table  set stock_remaing =${new_stock} id=${goodsId};

并发批改数据库存超卖

如果数据库事务的隔离级别不是串行化(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} 
where id = 商品 id
and remaing_stock>${quantity};

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

能够应用 redis 进行库存的抵扣么?

因为没有钻研过 redis 源码,对于这种形式参考了大牛的回复,答案是能够应用 redis 的事务性扣减余额,但在 CAS 机制上比 mysql 没有劣势,高性能是因为其内存存储的起因,带来的副作用是数据有失落危险。

原文链接:https://blog.csdn.net/new_com…

版权申明:本文为 CSDN 博主「iloveoverfly」的原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接及本申明。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿 (2021 最新版)

2. 劲爆!Java 协程要来了。。。

3. 最新!Log4j 2.x 再发版,正式解决核弹级破绽,又要熬夜了。。。

4.Spring Boot 2.6 正式公布,一大波新个性。。

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版