国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

PHP+Redis并發下單(代碼全篇)

CKJOKER / 451人閱讀

摘要:連接信息可以用原生也可以用其它的框架集成鎖定默認過期時間避免死鎖新版已經集成了大多數集成操作解鎖業務相關的可以是庫存物品數等用戶相關的下單下單個數用戶場次是為了方便異常處理方便數據查找商品場次此方法不具備原子

ip = $config["ip"];
            }
            if(isset($config["port"])){
                $this->ip = $config["port"];
            }
        }
        /**
         * Redis連接信息可以用原生,也可以用其它的框架集成
         */
        $this->_redis = new Redis();
        $this->_redis->connect($this->ip,$this->port);

    }


    /** 鎖定
     * @param int $intTimeout 默認過期時間(避免死鎖)
     * @return bool
     */
    private function lock($intTimeout = 8) {
        #新版set,已經集成了大多數集成操作
        $strRet   = $this->_redis->set($this->_lockKey, time().rand(10000,99999).rand(1000,9999).rand(100,999), "ex", $intTimeout, "nx");
        if($strRet) {
            return true;
        }else{
            return false;
        }
    }


    /** 解鎖
     * @throws Exception
     */
    private function unlock()
    {
        $strRet   = $this->_redis->del($this->_lockKey);
        if($strRet) {
            return true;
        }else{
            if($this->_redis->get($this->_lockKey)) {
              return false ;
            }else{
              return false ;
            }
        }
    }

    /**
     * 業務相關的key,可以是庫存,物品數等
     */
    const ORDER_KEY = "order_num";

    /**
     * 用戶相關的key
     */
    const USER_KEY = "user_num";

    /** Redis下單
     * @param int $num 下單個數
     * @param string $userId 用戶ID
     *
     * 場次是為了方便異常處理,方便數據查找
     * @param string $bout 商品場次 => order_num:1 , order_num:2
     * @return bool
     * @throws Exception
     */
     public function order( string $userId ,string $bout = "1" ,int $num = 1)
    {
        $orderKey = self::ORDER_KEY.":".$bout ;
        $userKey  = self::USER_KEY.":".$bout ;
        //此方法不具備原子性 并發處理是不能做條件判斷
        //$len = $this->_redis->llen();
        #實際為n+1次觸發完結,這里只做Redis自減
        $check = $this->_redis->lpop($orderKey);
        if(!$check){
            #當前order_num已經為0!
            //自動補貨為 100 ,$bout有一定的處理規則,不能亂傳
            self::autoBuild(100,$bout);
            return false ;
        }
        //特殊處理,避免n+1次的情況
        $len = $this->_redis->llen($orderKey) ;
        if($len == 0) {
            //自動補貨為 100 ,$bout有一定的處理規則,不能亂傳
            self::autoBuild(100,$bout);
            return false ;
        }
        //添加用戶數據
        $result = $this->_redis->lpush($userKey,$userId);
        if($result){
            return true ;
        }else{
            return false ;
        }
    }


    /** 失敗處理
     * #增加當前庫存
     * #減少用戶庫存
     * @param string $num
     * @param string $userId
     * @param $bout
     * @return bool
     * @throws Exception
     */
    public function _out(string $num,string $userId,$bout)
    {
        #并發參與時,總庫存有5個,一共10次請求,成功5次,退款1次,實際庫存1次
        #失敗處理時和_buildOrder加上同一把鎖,避免更新下次庫存時,上次庫存累積
        #_out 和 _buildOrder 同時只能有一個在執行,不然鎖會報錯,也避免下不必要的死鎖
        self::lock();
        //減用戶庫存
        $user = $this->_redis->lpop(self::USER_KEY.":".$bout);
        if(!$user) {
           return false ;
        }
        //增加商品庫存
        $all  = $this->_redis->lpush(self::ORDER_KEY.":".$bout,$userId);
        if(!$all) {
           //TODO::這里需要做容錯處理,即再商品庫存增加失敗時,做記錄
           return false ;
        }
        self::unlock();
    }


    /** 自動構建
     * @param int $num
     * @param $bout
     * @throws Exception
     */
    private  function autoBuild( int $num ,$bout)
    {
        $a = $this->_redis->get(self::ORDER_KEY.":".$bout);
        if(!$a) {
            //庫存已完結
            $this->_buildOrder(self::ORDER_KEY.":".$bout,$num);
        }
    }


    /** 物品庫存規則
     * @param $orderKey
     * @param $num
     * @return string
     * @throws Exception
     */
    private function _buildOrder($orderKey,$num)
    {
        //鎖定
        self::lock();
        $ckNum = "0" ;#Redis操作后返回為string類型
        #總數 與$ckNum要相同類型 不然可能會出現判斷錯誤
        if($num < 0) {
            throw new Exception("商品數量錯誤!");
        }
        $beforeNum = 0 ;
        //上一次庫存判斷 ()
        if($beforeNum > 0) {
            throw new Exception("商品未售罄!");
        }
        //當前庫存判斷
        $length = $this->_redis->llen($orderKey);
        if($length > 0) {
            throw new Exception("商品已經存在!");
        }
        //生成當前庫存
        while ($ckNum < $num) {
            if($ckNum == $num) {
                break ;
            }else if($ckNum > $num){
                break ;
            }else{
                $ckNum = $this->_redis->lpush($orderKey,1) ;
                if($ckNum >=$num) {
                    break ;
                }
            }
        }
        //并發時 循環成功 redis不一定成功
        /*for ($i=1;$i<=$num ;$i++) {
            $ckNum = $this->_redis->lpush(self::$_allCoin.self::getNum().":".$coin,1);
            if($ckNum >= $num) {
                break ;
            }
        }*/
        //解鎖
        self::unlock();
        return $ckNum ;
    }
}

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30998.html

相關文章

  • 秒殺系統優化方案之緩存、隊列、鎖設計思路

    摘要:一為什么難秒殺系統難做的原因庫存只有一份,所有人會在集中的時間讀和寫這些數據。又例如搶票,亦與秒殺類似,瞬時流量更甚。 一、為什么難 ????秒殺系統難做的原因:庫存只有一份,所有人會在集中的時間讀和寫這些數據。例如小米手機每周二的秒殺,可能手機只有1萬部,但瞬時進入的流量可能是幾百幾千萬。又例如12306搶票,亦與秒殺類似,瞬時流量更甚。 主要需要解決的問題有兩個: 高并發對數據庫...

    dinfer 評論0 收藏0
  • PHP依賴注入(代碼全篇)

    摘要:依賴注入傳統的思路應用程序用到一個類就會創建類并調用類的方法。這樣你可以完全控制依賴關系,通過調整不同的注入對象,來控制程序的行為。例如類用到了,可以在不修改類代碼的情況下,改用。 依賴注入 傳統的思路 應用程序用到一個Foo類,就會創建Foo類并調用Foo類的方法。 假如這個方法內需要一個Bar類,就會創建Bar類并調用Bar類的方法。 而這個方法內需要一個Bim類,就會創建Bim...

    felix0913 評論0 收藏0
  • PHP面試題

    摘要:質量高在設計時,可重用現有的,在以前的項目的領域中已被測試過的類使系統滿足業務需求并具有較高的質量。代碼塊捕獲異常,并創建一個包含異常信息的對象。這樣可以解決超賣的問題,但是會導致文件得開銷很大。 6.你們公司是使用什么框架? 答:我們公司采用的是TP框架,運用的mysql+apache+php進行開發,因為TP框架是一個免費開源的,輕量級的php開發框架,而且是我們中國人自己開發的,...

    ls0609 評論0 收藏0
  • PHP 并發場景的幾種解決方案

    摘要:在秒殺,搶購等并發場景下,可能會出現超賣的現象,在語言中并沒有原生提供并發的解決方案,因此就需要借助其他方式來實現并發控制。借助文件排他鎖,在處理下單請求的時候,用鎖定一個文件,成功拿到鎖的才能處理訂單。 在秒殺,搶購等并發場景下,可能會出現超賣的現象,在PHP語言中并沒有原生提供并發的解決方案,因此就需要借助其他方式來實現并發控制。 列出常見的解決方案有: 使用隊列,額外起一個進程...

    neu 評論0 收藏0

發表評論

0條評論

CKJOKER

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<