首頁  >  文章  >  後端開發  >  php高併發測試:防止庫存超賣的案例講解

php高併發測試:防止庫存超賣的案例講解

WBOY
WBOY轉載
2022-04-08 09:32:547245瀏覽

在之前的文章《PHP高並發情形下怎麼防止商品庫存超賣》中,我們講到了關於在高並發情況下防止商品庫存超賣的相關問題,下面我們一起來看看防止庫存超賣之併發測試的相關內容,希望對大家有幫助。

php高併發測試:防止庫存超賣的案例講解

本文是基於《PHP高並發情況下怎麼防止商品庫存超賣》的測試案例。推薦學習:《PHP學習教學

#一、普通下單 

並發測試時product 表id =1 name = 稻花香米store = 15

请求总数30 每次10个并发
ab -n 30 -c 10 http://xxxxx.top/code/the_limit/add_order.php

結果:

有15 次庫存減少成功store 庫存出現了負數-7 8 次判斷為庫存不夠(庫存負數是不正確的不允許的)

二、unsigned 模式 

調整回product 表id =1 name = 稻花香米store = 15

请求总数30 每次10个并发
ab -n 30 -c 10 http://xxxxx.top/code/the_limit/unsigned.php

結果:

有15 次庫存減少成功store 庫存出現了負數-6 9 次判斷為庫存不夠(庫存負數是不正確的不允許的)

僅在查詢語句上加for update 加鎖效果不大

三、mysql 的事務,鎖定作業的行 

調整回product 表id =1 name = 稻花香米store = 15

请求总数30 每次10个并发
ab -n 30 -c 10 http://xxxxx.top/code/the_limit/ACID.php

#結果:

有15 次庫存減少成功store 庫存未出現負數15 次判斷為庫存不夠(庫存負數是不正確的不允許的)

加事務效果不錯ab -n 3000 -c 1000 並行也能扛住

四、 非阻塞的文件排他鎖定

  •  阻塞形式

  •  非阻塞形式

效果也沒有出現負數但效能上:交易> 封鎖> 非阻塞

五、 redis 佇列

程式碼與之前略有調整樂觀鎖版

<?php
$redis =new Redis();
$redis->connect("127.0.0.1", 6379);
$redis->auth(&#39;PASSWORD&#39;);
$redis->watch(&#39;sales&#39;);//乐观锁 监视作用 set()  初始值0
$sales = $redis->get(&#39;sales&#39;);
//var_dump($sales); exit;

db();
global $con;
// 查询商品信息
//$product_id = 1;
//$sql = "select * from products where id={$product_id}";
//$result = mysqli_query($con, $sql);
//$row = mysqli_fetch_assoc($result);
//$store = $row[&#39;store&#39;];
// 库存
$n = 15;
if ($sales >= $n) {
    insertLog(&#39;库存为0 秒杀失败&#39;);
    exit(&#39;秒杀结束&#39;);
}

//redis开启事务
$redis->multi();
$redis->incr(&#39;sales&#39;); //将 key 中储存的数字值增一 ,如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
$res = $redis->exec(); //成功1 失败0

if ($res) {
    //秒杀成功
    $con = new mysqli(&#39;localhost&#39;,&#39;root&#39;,&#39;PASSWORD&#39;,&#39;dev&#39;);
    if (!$con) {
        echo "数据库连接失败";
    }

    $product_id = 1;// 商品ID
    $buy_num = 1;// 购买数量
    sleep(1);

    $sql = "update products set store=store-{$buy_num} where id={$product_id}";

    if (mysqli_query($con, $sql)) {
        echo "秒杀完成";
        insertLog(&#39;恭喜 秒杀成功&#39;);
    }

} else {
    insertLog(&#39;抱歉 秒杀失败&#39;);
    exit(&#39;抢购失败&#39;);
}

function db()
{
    global $con;
    $con = new mysqli(&#39;localhost&#39;,&#39;root&#39;,&#39;WOrd1234.*&#39;,&#39;dev&#39;);
    if (!$con) {
        echo "数据库连接失败";
    }
}

/**
 * 记录日志
 */
function insertLog($content)
{
    global $con;
    $sql = "INSERT INTO `order_log` (content) values(&#39;$content&#39;)";
    mysqli_query($con, $sql);
}
ab -n 30 -c 10 http://xxxxxx.top/code/the_limit/optimistic\ _redis_lock.php

最終結論並發挑戰優先redis 性能好

推薦學習:《PHP影片教學

以上是php高併發測試:防止庫存超賣的案例講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:learnku.com。如有侵權,請聯絡admin@php.cn刪除