zoukankan      html  css  js  c++  java
  • 项目秒杀思路(转)

    在做一个团购项目,遇到个问题,就是在抢购、秒杀、抽奖等活动时,库存数量有限,但是同时下单人数超过了库存数量,就会导致商品超售问题。那么我们怎么来解决这个问题呢,我的思路如下: 

    sql1:查询商品库存
    if(库存数量 > 0)
    {
      //生成订单...
      sql2:库存-1
    }

    当没有并发时,上面的流程看起来是如此完美,假设同时两个人下单,而库存只有1个了,在sql1阶段两个人查询到的库存都是>0的,于是最终都执行了sql2,库存最后变为-1,超售了,要么补库存,要么等用户投诉吧。

    解决这个问题比较流行的思路:
    1.用额外的单进程处理一个队列,下单请求放到队列里,一个个处理,就不会有并发的问题了,但是要额外的后台进程以及延迟问题,不予考虑。


    2.数据库乐观锁,大致的意思是先查询库存,然后立马将库存+1,然后订单生成后,在更新库存前再查询一次库存,看看跟预期的库存数量是否保持一致,不一致就回滚,提示用户库存不足。


    3.根据update结果来判断,我们可以在sql2的时候加一个判断条件update ... where 库存>0,如果返回false,则说明库存不足,并回滚事务。


    4.借助文件排他锁,在处理下单请求的时候,用flock锁定一个文件,如果锁定失败说明有其他订单正在处理,此时要么等待要么直接提示用户"服务器繁忙"

    5.使用redis队列来,入列出来列

    本文要说的是第4种方案,大致代码如下:
    阻塞(等待)模式
    <?php
    $fp = fopen("lock.txt", "w+");
    if(flock($fp,LOCK_EX))   //锁定当前指针,,,
    {
      //..处理订单
      flock($fp,LOCK_UN);
    }
    fclose($fp);
    ?>


    非阻塞模式
    <?php
    $fp = fopen("lock.txt", "w+");
    if(flock($fp,LOCK_EX | LOCK_NB))
    {
      //..处理订单
      flock($fp,LOCK_UN);
    }
    else
    {
      echo "系统繁忙,请稍后再试";
    }
    fclose($fp);
    ?>

    3.redis 高并发队列秒杀

    <?php
    $store=50;
    $redis=new Redis();
    $result=$redis->connect('127.0.0.1',6379);
    $res=$redis->llen('pro38');
    echo $res;
    $count=$store-$res;
    for($i=0;$i<$count;$i++){
    	$redis->lpush('pro38',1);
    }
    echo $redis->llen('pro38');
    ?>

    上面是添加一个库存为50的redis的list

    下面贴上下单代码

    <?php
    include "MMysql.class.php";
    $configArr=[
    	'host'=>'121.41.38.44',
    	'port'=>'3306',
    	'user'=>'yuancheng',
    	'passwd'=>'yuancheng',
    	'dbname'=>'laiyifendb',
    ];
    $db = new MMysql($configArr);
    $redis=new Redis();
    $result=$redis->connect('127.0.0.1',6379);
    
    $count=$redis->lpop('pro38');
    if(!$count){
    	echo "error:no store redis";
    	return;
    }
    $sql="select * from sdb_b2c_products where product_id='38'";
    $product=$db->doSql($sql);
    if(!$product){
    	echo "error:not find product";
    	return;
    }
    $product=$product[0];
    if($product['store']-$product['freez']<1){
    	echo "error:no store";
    	return;
    }
    $sql="select * from sdb_b2c_member_addrs where member_id='256187'";
    $addr=$db->doSql($sql);
    $addr=$addr[0];
    $data=[
    	'order_id'=>date('ymdHis').rand(100,999),
    	'total_amount'=>$product['price'],
    	'final_amount'=>$product['price'],
    	'pay_status'=>'0',
    	'createtime'=>time(),
    	'shipping_id'=>'13',
    	'shipping'=>'韵达',
    	'member_id'=>'636389',
    	'ship_area'=>$addr['area'],
    	'shipname'=>$addr['name'],
    	'ship_addr'=>$addr['addr'],
    ];
    $order=$db->insert('sdb_b2c_orders',$data);
    if($order){
    	$sql="update sdb_b2c_products set freez=freez+1 where product_id='38'";
    	$db->doSql($sql);
    	echo "order create success";
    	return;
    }else{
    	echo "error:order create fail";
    	return;
    }
    
    ?>



    经过测试,此方法可以防止超卖的发生

  • 相关阅读:
    Leetcode 191.位1的个数 By Python
    反向传播的推导
    Leetcode 268.缺失数字 By Python
    Leetcode 326.3的幂 By Python
    Leetcode 28.实现strStr() By Python
    Leetcode 7.反转整数 By Python
    Leetcode 125.验证回文串 By Python
    Leetcode 1.两数之和 By Python
    Hdoj 1008.Elevator 题解
    TZOJ 车辆拥挤相互往里走
  • 原文地址:https://www.cnblogs.com/MyIsLu/p/6519007.html
Copyright © 2011-2022 走看看