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

資訊專欄INFORMATION COLUMN

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

CKJOKER / 460人閱讀

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

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 默認(rèn)過期時間(避免死鎖)
     * @return bool
     */
    private function lock($intTimeout = 8) {
        #新版set,已經(jīng)集成了大多數(shù)集成操作
        $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 ;
            }
        }
    }

    /**
     * 業(yè)務(wù)相關(guān)的key,可以是庫存,物品數(shù)等
     */
    const ORDER_KEY = "order_num";

    /**
     * 用戶相關(guān)的key
     */
    const USER_KEY = "user_num";

    /** Redis下單
     * @param int $num 下單個數(shù)
     * @param string $userId 用戶ID
     *
     * 場次是為了方便異常處理,方便數(shù)據(jù)查找
     * @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 ;
        //此方法不具備原子性 并發(fā)處理是不能做條件判斷
        //$len = $this->_redis->llen();
        #實際為n+1次觸發(fā)完結(jié),這里只做Redis自減
        $check = $this->_redis->lpop($orderKey);
        if(!$check){
            #當(dāng)前order_num已經(jīng)為0!
            //自動補(bǔ)貨為 100 ,$bout有一定的處理規(guī)則,不能亂傳
            self::autoBuild(100,$bout);
            return false ;
        }
        //特殊處理,避免n+1次的情況
        $len = $this->_redis->llen($orderKey) ;
        if($len == 0) {
            //自動補(bǔ)貨為 100 ,$bout有一定的處理規(guī)則,不能亂傳
            self::autoBuild(100,$bout);
            return false ;
        }
        //添加用戶數(shù)據(jù)
        $result = $this->_redis->lpush($userKey,$userId);
        if($result){
            return true ;
        }else{
            return false ;
        }
    }


    /** 失敗處理
     * #增加當(dāng)前庫存
     * #減少用戶庫存
     * @param string $num
     * @param string $userId
     * @param $bout
     * @return bool
     * @throws Exception
     */
    public function _out(string $num,string $userId,$bout)
    {
        #并發(fā)參與時,總庫存有5個,一共10次請求,成功5次,退款1次,實際庫存1次
        #失敗處理時和_buildOrder加上同一把鎖,避免更新下次庫存時,上次庫存累積
        #_out 和 _buildOrder 同時只能有一個在執(zhí)行,不然鎖會報錯,也避免下不必要的死鎖
        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();
    }


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


    /** 物品庫存規(guī)則
     * @param $orderKey
     * @param $num
     * @return string
     * @throws Exception
     */
    private function _buildOrder($orderKey,$num)
    {
        //鎖定
        self::lock();
        $ckNum = "0" ;#Redis操作后返回為string類型
        #總數(shù) 與$ckNum要相同類型 不然可能會出現(xiàn)判斷錯誤
        if($num < 0) {
            throw new Exception("商品數(shù)量錯誤!");
        }
        $beforeNum = 0 ;
        //上一次庫存判斷 ()
        if($beforeNum > 0) {
            throw new Exception("商品未售罄!");
        }
        //當(dāng)前庫存判斷
        $length = $this->_redis->llen($orderKey);
        if($length > 0) {
            throw new Exception("商品已經(jīng)存在!");
        }
        //生成當(dāng)前庫存
        while ($ckNum < $num) {
            if($ckNum == $num) {
                break ;
            }else if($ckNum > $num){
                break ;
            }else{
                $ckNum = $this->_redis->lpush($orderKey,1) ;
                if($ckNum >=$num) {
                    break ;
                }
            }
        }
        //并發(fā)時 循環(huán)成功 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 ;
    }
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/30998.html

相關(guān)文章

  • 秒殺系統(tǒng)優(yōu)化方案之緩存、隊列、鎖設(shè)計思路

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

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

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

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

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

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

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

    neu 評論0 收藏0

發(fā)表評論

0條評論

CKJOKER

|高級講師

TA的文章

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