亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

CKJOKER / 517人閱讀

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

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)過期時(shí)間(避免死鎖)
     * @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 下單個(gè)數(shù)
     * @param string $userId 用戶ID
     *
     * 場(chǎng)次是為了方便異常處理,方便數(shù)據(jù)查找
     * @param string $bout 商品場(chǎng)次 => 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();
        #實(shí)際為n+1次觸發(fā)完結(jié),這里只做Redis自減
        $check = $this->_redis->lpop($orderKey);
        if(!$check){
            #當(dāng)前order_num已經(jīng)為0!
            //自動(dòng)補(bǔ)貨為 100 ,$bout有一定的處理規(guī)則,不能亂傳
            self::autoBuild(100,$bout);
            return false ;
        }
        //特殊處理,避免n+1次的情況
        $len = $this->_redis->llen($orderKey) ;
        if($len == 0) {
            //自動(dòng)補(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ā)參與時(shí),總庫存有5個(gè),一共10次請(qǐng)求,成功5次,退款1次,實(shí)際庫存1次
        #失敗處理時(shí)和_buildOrder加上同一把鎖,避免更新下次庫存時(shí),上次庫存累積
        #_out 和 _buildOrder 同時(shí)只能有一個(gè)在執(zhí)行,不然鎖會(huì)報(bào)錯(cuò),也避免下不必要的死鎖
        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::這里需要做容錯(cuò)處理,即再商品庫存增加失敗時(shí),做記錄
           return false ;
        }
        self::unlock();
    }


    /** 自動(dòng)構(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要相同類型 不然可能會(huì)出現(xiàn)判斷錯(cuò)誤
        if($num < 0) {
            throw new Exception("商品數(shù)量錯(cuò)誤!");
        }
        $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ā)時(shí) 循環(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)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/30998.html

相關(guān)文章

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

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

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

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

    felix0913 評(píng)論0 收藏0
  • PHP面試題

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

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

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

    neu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

CKJOKER

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<