一、概述
电商平台中,订单模块的一个非常重要的点就是防止商品超卖。什么叫商品超卖,就是用户显示下单成功,但库存因为并发的原因扣减成了负数,造成实际商品量不足,无法发货。如果用户已支付,则需要进行退款操作。
二、解决思路
【解决思路】对下单流程进行加锁,同一时间仅支持一个线程进行下单。
三、解决方案
1、对下单流程加锁
这种方式对整个下单流程进行加锁,简单粗暴,但弊端非常明显。比如一个请求处理时间为100ms,1000个人请求,响应时间就达到了100s,1分钟以上,用户很难接受。
2、利用数据库行锁
【原理】
当对字段进行修改时,数据库会加一个行锁,我们将修改的条件设置成(库存-订单商品数>=0)。如果修改成功,即修改记录数大于0,则下单成功;否则库存不足,抛出异常,利用事务进行回滚。
注意:没有索引的时候,就是表锁,所以我们一定要加索引。通常建表时约定必须要有主键Id,即可避免,详细说明可以参考链接:https://blog.csdn.net/u013043762/article/details/80454396
【适合场景】
该模式对数据库的压力比较大,小量的并发可以满足。
当库存充足,并发量高时,会存在后续用户响应时间长的问题。
当库存较少,并发量高时,虽然不会再执行创建订单的逻辑,但是每个用户都在对数据库进行查询,依然存在数据库压力较大的问题。
【关键代码】
@Override
@Transactional
public void order() {
//减扣库存:成功后再增订单
storeDeduction(1L, 3);
//新增订单
TblOrderEntity entity = new TblOrderEntity();
saveEntity(entity);
//新增订单详情
TblOrderDetailEntity detailEntity = new TblOrderDetailEntity();
detailEntity.setGoodId(1L);
detailEntity.setGoodCount(3);
detailEntity.setOrderId(entity.getId());
tblOrderDetailService.saveEntity(detailEntity);
}
//库存减扣
private void storeDeduction(Long goodId, Integer count) {
//查询库存
TblGoodEntity goodEntity = tblGoodService.getById(goodId);
if (goodEntity.getStoreCount() > count) {
//减扣库存
Integer consumeStock = tblGoodService.consumeStock(goodId, count);
if (consumeStock <= 0) {
throw new OpenException("库存不足");
}
} else {
throw new OpenException("库存不足");
}
}
<update id="consumeStock">
update tbl_good set store_count = store_count - #{count} where id=#{goodId} and store_count >= #{count}
</update>
3、
四、压力测试
网友评论