最近在做公司电商产品的需求,通过多种方式了解了电商,针对商品设计的重点和难点个人感觉主要认为有两方面:
- 一是商品的多规格设计
- 二是分布式环境下库存并发增减的处理
针对于库存的增减,处理不好很可能造成库存的超卖,及数据不一致问题(实际售出数量与针对于每个SKU库存的减量不一致,一般情况是售出数量多于SKU减量)现在讨论下针对于 高并发分布式环境库存的增减(防止超卖问题):
针对于单SKU减库存(每次只减一个库存)的操作:
方案一:
利用数据库行锁的特点,修改同一条数据,事务一中修改这条数据完毕 但事务还未提交,另一个事务中也需要修改该数据,到修改该数据操作时会一直等待,直到事务一提交事务释放行锁为止。事务二才会继续执行的特点(mysql更新操作默认的锁级别是行级的)。
update t_goods_sku t set t.goods_storage= t.storage - a where t.sku_id = b and t.goods_storage -a > 0
减库存失败则返回0 成功则返回受影响的行数(也就是1)。
也需大家会这样想,这样做肯定就万无一失了,利用mysql行锁的特性就能防止超卖现象的产生。其实考虑的还不够。如果你使用的是Oracle数据库,也许会达到你想要的效果(oracle默认的事务隔离级别是读已提交,其他事务提交的内容会在自己事务内及时的显现),如果是mysql并且采用默认的事务隔离级别的配置,在高并发环境下会出现问题(mysql事务隔离级别是可重复读,即其他事务修改的内容在自己事物里无法及时的显现,出现幻读的现象)。 需要针对默认的事务隔离级别做响应的修改。
所以如果对于单SKU增减的话 利用sql语句、行锁 、事务隔离级别的特点,针对于普通数据量,并发小的网站是可以满足需求的。
优点:实现简单,支持分布式,库存的实时性比较高
缺点:对数据库频繁操作导致数据库负载高
事务隔离级别可以通过设置mysql全局事务配置,也可以使用spring事务控制器中配置单事务隔离级别。
方案二:
单针对于以上缺点可以采用相应的优化手段,数据库中数据的操作主要包括读和写:
针对于读操作,可以采用分布式缓存处理,首先同步RDB 的SKU数据,读写操作
---------------------------------------未完待续
针对于多SKU批量减(每次减多个库存)操作:
方案一:
针对这个问题,如果是分布式环境,首先我们想到的是减库存这个操作 让位于不同机器上的程序去串行执行,这样就能保证一台机器的写操作对 另一台机器上的写数据可见。(可以采用分布式锁实现)
缺点:违背了分布式的设计初衷,不同机器上的程序并行执行的初衷被违背了,并且串行执行只能单节点执行某段程序,导致程序效率极其低下。
方案二:
参考文章:https://my.oschina.net/LucasZhu/blog/1798655