我理解是防止超卖的一个场景,由于这块是高并发的场景下,频繁操作数据库,会造成性能问题,这块分两部分处理,一部分是从业务层控制冻结库存,从理财货架选择商品点击申购后,跳到收银台提交支付,在提交支付的动作里面进行剩余份额确认,当前我们是进行缓存查询,查询当前的剩余份额>申购份额时,则把这部分份额进行冻结处理,然后首先保证前端显示的剩余库存已被减掉,防止超卖。等支付成功之后,再把真实份额减掉,如果支付失败则释放冻结的份额。
另外一部分是底层数据库操作扣减库存逻辑,首先采用事务控制,我们通常会采用try, catch(rollback), commit模式在一个事物里面,在真实更新数据库的库存时,要先进行一个update操作得到真实的扣完剩余库存,再判断该值是否大于0,如果小于0则抛异常进行catch回滚,更新库存失败,保证在高并发下不会导致库存为负数。
beginTranse(开启事务)
try{
//quantity为请求减掉的库存数量
$dbca->query('update s_store set amount = amount - quantity where postID = 12345');
$result = $dbca->query('select amount from s_store where postID = 12345');
if(result->amount < 0){
throw new Exception('库存不足');
}
}catch($e Exception){
rollBack(回滚)
}
commit(提交事务)
另外,更简洁的方法:
beginTranse(开启事务)
try{
//quantity为请求减掉的库存数量
$dbca->query('update s_store set amount = amount - quantity where amount>=quantity and postID = 12345');
}catch($e Exception){
rollBack(回滚)
}
commit(提交事务)
我们在数据库层也会采用加锁机制(乐观锁,时间戳或者version)去控制并发修改统一记录的情况。
或者通过服务端的内存锁(锁主键)。当某个用户要修改某个id的数据时,把要修改的id存入memcache,若其他用户触发修改此id的数据时,读到memcache有这个id的值时,就阻止那个用户修改
尽量去减少数据库的大并发读写压力,通过缓存或队列方式降低读写操作。
或者针对产品名称+uid为唯一索引,控制并发。