项目秒杀思路(转)
在做一個團購項目,遇到個問題,就是在搶購、秒殺、抽獎等活動時,庫存數(shù)量有限,但是同時下單人數(shù)超過了庫存數(shù)量,就會導(dǎo)致商品超售問題。那么我們怎么來解決這個問題呢,我的思路如下:?
sql1:查詢商品庫存
if(庫存數(shù)量 > 0)
{
? //生成訂單...
? sql2:庫存-1
}
當沒有并發(fā)時,上面的流程看起來是如此完美,假設(shè)同時兩個人下單,而庫存只有1個了,在sql1階段兩個人查詢到的庫存都是>0的,于是最終都執(zhí)行了sql2,庫存最后變?yōu)?1,超售了,要么補庫存,要么等用戶投訴吧。
?
解決這個問題比較流行的思路:
1.用額外的單進程處理一個隊列,下單請求放到隊列里,一個個處理,就不會有并發(fā)的問題了,但是要額外的后臺進程以及延遲問題,不予考慮。
2.數(shù)據(jù)庫樂觀鎖,大致的意思是先查詢庫存,然后立馬將庫存+1,然后訂單生成后,在更新庫存前再查詢一次庫存,看看跟預(yù)期的庫存數(shù)量是否保持一致,不一致就回滾,提示用戶庫存不足。
3.根據(jù)update結(jié)果來判斷,我們可以在sql2的時候加一個判斷條件update ... where 庫存>0,如果返回false,則說明庫存不足,并回滾事務(wù)。
4.借助文件排他鎖,在處理下單請求的時候,用flock鎖定一個文件,如果鎖定失敗說明有其他訂單正在處理,此時要么等待要么直接提示用戶"服務(wù)器繁忙"
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 "系統(tǒng)繁忙,請稍后再試";
}
fclose($fp);
?>
3.redis 高并發(fā)隊列秒殺
<?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; }?>經(jīng)過測試,此方法可以防止超賣的發(fā)生
轉(zhuǎn)載于:https://www.cnblogs.com/MyIsLu/p/6519007.html
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎!定制產(chǎn)品紅包拿不停!總結(jié)
- 上一篇: QT Windows下生成动态链接库
- 下一篇: Linux shell - 重命名文件和