搶購、秒殺是平常很常見的場景,面試的時候面試官也經常會問到,比如問你**中的搶購秒殺是怎麼實現的等等。
搶購、秒殺實現很簡單,但是有些問題需要解決,主要針對兩個問題:
一、高併發對資料庫產生的壓力
二、競爭狀態下如何解決庫存的正確減少("超賣"問題)
第乙個問題,對於php來說很簡單,用快取技術就可以緩解資料庫壓力,比如memcache,redis等快取技術。
第二個問題就比較複雜點:
常規寫法:
查詢出對應商品的庫存,看是否大於0,然後執行生成訂單等操作,但是在判斷庫存是否大於0處,如果在高併發下就會有問題,導致庫存量出現負數(超賣)。
例如(1)a購買商品,查詢庫存為1,可以購買
(2)減少庫存,提交訂單
(1)和(2)之間執行是有時間的,這中間b也來購買這個商品,他查詢出的庫存也是1,之後提交訂單,庫存就會變為-1
例如(1)a購買商品,查詢庫存為1,可以購買
(2)b購買商品,查詢庫存為1,可以購買(出現髒讀)
(3)a提交訂單,減少庫存,庫存減至0
(4)b提交訂單,減少庫存,庫存減至-1
<?php
$conn
=mysql_connect
("localhost"
,"root"
,"root");
if(!$conn
)mysql_select_db
("test"
,$conn);
$price=10
;$user_id=1
;$goods_id=1
;$sku_id=11
;$number=1
;//生成唯一訂單號
function
build_order_no()
//記錄日誌
function
add_num_log
($event
,$type=0
)//模擬下單操作
//庫存是否大於0
$sql
="select number from ih_store where goods_id='$goods_id
' and sku_id='$sku_id'";
$rs=
mysql_query
($sql
,$conn);
$row
=mysql_fetch_assoc
($rs);
if($row
['number'
]>0)
where sku_id='$sku_id'";
$store_rs
=mysql_query
($sql
,$conn);
if(mysql_affected_rows()
)else
}else
下面是redis的樂觀鎖思路
例如(1)a購買商品,獲取庫存為2(版本1)
(2)b購買商品,獲取庫存為2(版本1)
(3)a提交訂單,減少庫存,比較版本,一致則執行,庫存減至1(更新後的版本為2)
(4)b提交訂單,減少庫存,比較版本,不一致會阻止執行
<?php
$redis
=new
redis()
;$redis
->
connect
('127.0.0.1'
,6379);
$redis
->
watch
('number');
//在提交時檢測會不會被多人修改,版本是否一致
//從redis中獲得庫存
$number
=$redis
->
get(
'number');
if($number
<=0)
$redis
->
multi()
;//標記乙個事務塊的開始
$redis
->
decr
('number');
//redis內庫存減少
$result
=$redis
->
exec()
;//結束,檢測版本號,不一致會阻止執行if(
$result)(
//mysql操作
)
至於為什麼不使用悲觀鎖和佇列
1、不使用悲觀鎖,因為等待時間非常長,響應慢
2、不使用佇列,因為併發量會讓佇列記憶體瞬間公升高
以上就是php+redis實現秒殺的思路,實際的業務處理會更複雜,酌情參考。
php redis解決高併發案例
本指令碼依賴 php redis擴充套件,請自行安裝 商品 class good public function get string name throw new exception method not exists name todo implement get method.增加庫存 par...
高併發下搶購
了解高併發以及怎麼處理後,測試一下專案中下單的 邏輯很簡單,goods表中stock設定為unsigned。剛開始你可能會覺得這樣會出現超單的情況,但是測試後,沒有出現超單的情況。看似沒有問題,但是看過日誌發現問題還挺多的。這之前請看下這篇文章裡面有處理高併發下單的情況。goods id num g...
高併發下的HashMap
1.hashmap在插入元素過多的時候需要進行resize,resize的條件是 hashmap.size capacity loadfactor。2.hashmap的resize包含擴容和rehash兩個步驟,rehash在併發的情況下可能會形成鍊錶環 hashmap進行儲存時,假設size超過當...