在商品购买的过程中,库存的抵扣过程,一般操作如下: 上述过程的伪代码如下: 并发修改数据库存超卖 如果数据库事务的隔离级别不是串行化(serializable),根据事务的特性,在并发修改的时候,可能会出现写覆盖的问题。假设,商品的剩余库存stock_remaing 为100,客户A下单20,客户B下单30,在并发扣库存的时候,可能存在超卖。如果客户A和客户B同时获取剩余库存为100,则会出现事务后提交的值会覆盖前一个客户提交的值,有可能剩余的库存是80或者70。流程如下: 加锁更新存库 为了在事务控制中,防止写覆盖,你会想到使用select for update的方式,将该商品的库存锁住,然后执行余下的操作。流程如下: 以上,使用悲观锁方式,在分布式服务中,如果并发情况比较高的时候,扣减库存的操作是串行操作,效率很低。 使用乐观锁的方式更新 在更新的时候,使用(CAS+版本号更新)+重试条件(重试次数或者重试时间限制)乐观锁的方式更新库存(乐观锁的操作过程可以参考使用Spring AOP+注解基于CAS方式实现java的乐观锁)。此时,如果,客户A和客户B同时读取到库存剩余100,在更新的时候,有一个操作会失败。流程如下: 该种方式可以大大提高并发性,也可以保证数据的一致性;通过重试次数和重试时间的条件控制,可以防止过多的重试带来的数据库压力。 可以使用直接递减的方式执行么? 在抵扣库存的时候,有的人提议不执行select,计算,set三段式的操作,直接扣减的方式,并且对于扣减到小于零的情况作了判断。伪代码如下: 在分布式服务调用中,因为网络异常,获取服务器异常,可能在微服务调用时,存在服务重试。例如,场景的网关超时,服务重试机制。此时,该种方式不满足幂等性,而存在多扣的情况。 可以使用redis进行库存的抵扣么? 由于没有研究过redis源码,对于这种方式参考了大牛的回复,答案是可以使用redis的事务性扣减余额,但在CAS机制上比mysql没有优势,高性能是因为其内存存储的原因,带来的副作用是数据有丢失风险。详情可以参考沈剑大神的(余额并发扣减一致性,能否使用redis事务?)
// 根据商品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};
update stock_table set remaing_stock=remaing_stock-${quantity} where id =商品id and remaing_stock>${quantity};
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算