高并发下抢购

    了解高并发以及怎么处理后,测试一下项目中下单的代码,逻辑很简单,goods表中stock设置为unsigned。刚开始你可能会觉得这样会出现超单的情况,但是测试后,没有出现超单的情况。看似没有问题,但是看过日志发现问题还挺多的。这之前请看下这篇文章里面有处理高并发下单的情况。http://www.php.cn/php-weizijiaocheng-350323.html

$goods_id;
$num;
$goods_model = GoodsModel::self();
$goods = $goods_model->where('id', $goods_id)->field('stock')->find();
if ($goods['stock'] < $num) {
    return false;
}
$goods_model->startTrans();
try {
    //商品库存减成功后下单
    if ($goods_model->where('id', $goods_id)->setDec('stock', $num)) {
         //下单处理
         $order_data;
         $order_model->insert($order_data);
         if ($goods['stock'] - $num == 0) {
             //库存为0自动下架
             $goods_model->where('id', $goods_id)->update(['state', 0]);
         }
         $goods_model->commit();
    }
} catch (\Exception $e) {
    $goods_model->rollback();
}

    这里无意间用了上述文章中的优化方案一,没有超单得亏了数据库字段有设置stock为unsigned,导致很多请求其实有报错信息:Numeric value out of range: 1690 BIGINT UNSIGNED value is out of range。其次是很多请求已经通过了下单的判断(这里实在是阻止不了多个请求同时通过这个判断),最后是库存为0后商品并没有自动下架。要解决上述情况还有要加上优化方案二里的加锁。加了锁后问题都解决了。

$goods = $goods_model->where('id', $goods_id)->field('stock')->lock(true)->find();

    我一直不喜欢锁,1是不太了解锁的原理,2是有各种锁,乐观锁,悲观锁等,3是锁很耗数据库性能,但是不加的话又会出现问题。这里用了主键id查询,锁的是行数据,如果不是用了主键,锁的是整个数据表,很影响性能的(怎么个影响法也没仔细研究,容易出现死锁吧)。虽然不喜欢用锁,但是很多涉及到重要字段(即使不是高并发的情况)的地方都会加锁,之前就是有一个地方没加锁,导致用户资金出现问题,幸亏早发现。

    网上很多都是说用redis队列的,提前创建列表,然后pop数据,因为redis是单线程而且是原子性的,保证不会超单。这种也试了,是可行的,网上也有很多教程就不细说了。

    总结一下,数据库字段哪些不能负数的都设置为unsigned,一些重要的操作加事务和加锁,这样就可以避免很多问题。当然这些不会是最好的做法,却是最简单最好用能解决大多问题的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值