php使用redis實現最簡單秒殺功能 僅供參考

秒殺問題主要涉及到的是 指定商品的數量還有突然的併發

先展示下正常的寫法

        //查詢商品數量 $goodsNum = 10

        if ($goodsNum > 0) {
            //對商品數量進行自減1 
            if (自減成功) {
                //將用戶添加到搶購成功表中
            }else{
                //搶購失敗
            }
        }else{
            //商品搶完了
        }

這樣寫可以實現功能,前提是沒有任何併發的時候,如果此時有100個用戶同時請求,有可能會有20多個請求同時到達if裏面,這樣就導致了商品數量變爲負數。

所以這個時候我們不單單使用mysql,再加上redis中的隊列做處理。因爲redis支持單線程,所以使用redis中隊列,保持隊列中元素先進先出,每次只出一個。

首先,先將商品加入到隊列中。

        $redis = new redis();
        $redis->connect("127.0.0.1","6379");
        //先將商品數量寫入到隊列中

        //商品數量 
        $goodsNum = 10;
        
        //商品列表隊列的redis
        $goodsList = "goodsList_1";

        //將商品依次加入隊列中
        for ($i=1; $i <= $goodsNum; $i++) { 
            $redis->lpush($goodsList,1);
        }

接下來就是商品的搶購了

        $redis = new redis();
        $redis->connect("127.0.0.1","6379");
        //先將商品數量寫入到隊列中

        //商品列表隊列的redis
        $goodsList = "goodsList_1";

        //模擬用戶id
        $userid = rand(1000,9999);

        //搶到商品的用戶集合
        $userList = 'userList_1';

        //出隊列
        if (!$redis->rpop($goodsList)) {
            //沒有商品 已經搶購完了
        }

        //將搶到的商品的用戶放進一個集合中
        if ($redis->lpush($userList,$userid)) {
            //搶購成功
        }else{
            //搶購失敗
        }

這樣基本就可以實現秒殺功能。但是如果該商品只允許用戶搶購成功一次,那還是有點瑕疵。所以在此改進。

        //所有搶購的用戶集合
        $waitUserList = "waitUserList_1";

        //搶購成功的用戶集合
        $userList = "userList_1";

        //模擬用戶
        $userid = rand(1000,9999);

        //商品列表隊列的redis
        $goodsList = "goodsList_1";

        //將所有進來的用戶存入
        if ($redis->hset($waitUserList,$userid,$userid)) {
            if ($redis->rpop($goodsList)) {
                //將用戶存入搶購成功集合
                $redis->hset($userList,$userid,$userid);
                //搶購成功
            }else{
                //商品搶完了
            }
        }

使用hset存用戶是因爲hash裏的值不允許重複,如果裏面有了鍵值是1的,此時hset就存不進去。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章