Redis 並發防止超賣


那么,既然“下單減庫存”和“付款減庫存”都有缺點,我們能否把兩者相結合,將兩次操作進行前后關聯起來,下單時先預扣,在規定時間內不付款再釋放庫存,即采用“預扣庫存”這種方式呢?

這種方案確實可以在一定程度上緩解上面的問題。但是否就徹底解決了呢?其實沒有!針對惡意下單這種情況,雖然把有效的付款時間設置為10分鍾,但是惡意買家完全可以在10分鍾后再次下單,或者采用一次下單很多件的方式把庫存減完。針對這種情況,解決辦法還是要結合安全和反作弊的措施來制止。

加鎖set是為了防止多機用戶同時訪問同一共享資源,即庫存數。

1.先扣減庫存,防止用戶搶購后未支付

2.定時任務掃描5分鍾內未支付訂單,並主動請求支付狀態

3.關閉訂單,重新釋放庫存

<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2020/7/7
* Time: 17:09
*/
//連接本地的 Redis 服務
/* Connect to an ODBC database using driver invocation */
$dsn = 'mysql:dbname=homestead;host=192.168.10.10';
$user = 'homestead';
$password = 'secret';


$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

//存儲數據到列表中
//for($i=0;$i<=10;$i++){
// $redis->lpush("goods_store",1);
//}
//var_dump($redis->lLen("goods_store"));
//exit;
$rand_num = rand(1,10);
//$rand_num =1;

//庫存獲取
$key = 'lock';
$random = rand(0,1000);
$ttl = time();
//NX :只在鍵不存在時,才對鍵進行設置操作。 SET key value NX 效果等同於 SETNX key value 。
//EX second :設置鍵的過期時間為 second 秒。 SET key value EX second 效果等同於 SETEX key second value 。
$rs = $redis->set($key, $random, array('nx', 'ex' => $ttl));
if ($rs) {
//處理更新緩存邏輯
$Len = $redis->lLen("goods_store");

//判斷庫存
if($Len >= $rand_num){

    //生成訂單數據
    //....

     //下面這一段屬於支付成功后執行,這樣可以防止有些搶購了未支付情況
try {
$dbh = new PDO($dsn, $user, $password);
$dbh->beginTransaction();
$sql = "UPDATE `Course` SET `order_number`=order_number-$rand_num WHERE (`c_id`='03')";
$sth = $dbh->exec($sql);
$dbh->commit();

// 獲取存儲的數據並輸出
for($i=1;$i<=$rand_num;$i++){
$arList = $redis->lpop("goods_store");
}
var_dump($redis->lLen("goods_store"),$arList);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
}

//先判斷隨機數,是同一個則刪除鎖
if ($redis->get($key) == $random) {
$redis->del($key);
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM