在商品购买的过程中,库存的抵扣过程,个别操作如下:
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 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!