Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erklärung von Flash-Sale-Produkten mit PHP in Kombination mit Redis

Detaillierte Erklärung von Flash-Sale-Produkten mit PHP in Kombination mit Redis

不言
不言Original
2018-05-09 11:52:344857Durchsuche

Dieser Artikel stellt hauptsächlich die detaillierte Erklärung von PHP in Kombination mit Redis-Flash-Sale-Produkten vor. Jetzt werde ich ihn mit Ihnen teilen Wenn Sie es brauchen, können sich Freunde auf

1 beziehen. Zuerst eine kleine Vorbereitung.

1.1 Erstellen Sie eine Produkttabelle, eine Bestelltabelle und initialisieren Sie die Daten

Bestelltabelle.


1.2 Produktdaten in die Redis-Warteschlange schreiben.

Zum Beispiel gibt es 100 Stück von Produkt Nr. 1. Schreiben Sie einfach 100 Einsen in die Warteschlange „goods_1“. Wenn Sie beispielsweise die Atomizität der Pop-Operation (Parallelität) verwenden, können Sie beim späteren Kauf einfach einen Pop-up nach dem Kauf hinzufügen.

//代码使用yii 框架,重点在思路,其它框架做少量调整即可。 
 $redis = self::createRedisObj(); //创建redis 对象,后面提供详细代码

        $sql = "select * from sec_goods";
        $rows = Yii::app()->db->createCommand($sql)->queryAll();

        foreach( $rows as $key => $row ):
            $goods_id = $row["id"];
            $stock_avail =  $row["stock_avail"];
            $redis_key = "goods_".$goods_id;
            for($i =0 ; $i< $stock_avail; $i++){
                $redis->lpush($redis_key , 1);
            }
            echo $goods_id."llen is ".$redis->lLen($redis_key)."<br/>";
        endforeach;

Wie unten nach Fertigstellung gezeigt. (In realen Situationen kann es im Hintergrund zu Bibliotheksanpassungen kommen und die Daten in Redis müssen entsprechend synchronisiert werden. Bitte achten Sie bei tatsächlichen Projekten darauf, was hier vorerst nicht angezeigt wird)

2 Wenn kein Redis vorhanden ist, der reguläre Kaufcode.

//用随机值模拟客户,商品,单次购买份数 
 $uid = rand(1,10);
        $amount = rand(1,5);
        $goods_id = rand(1,6);
        $time = time();
$this->buy($uid , $goods_id , $amount);

public function buy($uid , $goods_id , $amount){

     //使用行锁.
        try {
            $trans = Yii::app()->db->beginTransaction();

            $sql = "select stock_avail from sec_goods where id = $goods_id for update";  //
            $stock_avail = Yii::app()->db->createCommand($sql)->queryScalar();

            if( $stock_avail >= $amount ){  //份额足够。
                $sn = date("YmdHis")."-".$uid."-".$goods_id.rand(1000,9999);

                $sql = "insert into sec_order set sn = &#39;$sn&#39;,user_id = $uid, goods_id = $goods_id, create_at = $time,num = $amount";
                $bool = Yii::app()->db->createCommand($sql)->execute();
                if( !$bool ){ throw new Exception("执行失败".$sql); }

                $sql = "update sec_goods set stock_avail = stock_avail - $amount  where id= $goods_id";
                $bool = Yii::app()->db->createCommand($sql)->execute();
                if( !$bool ){ throw new Exception("执行失败".$sql); }
            }
            $trans->commit();
            return true;
        } catch (Exception $e) {
            //日志记录
            $trans->rollback();
            return false;
        }
}

Dann verwenden Sie zum Testen das Bauch-Gadget von Apache.
-n stellt die Anzahl der Anfragen dar. -c stellt die Anzahl gleichzeitiger Anfragen gleichzeitig dar.

ab -n 1000 -c 100 http://xxx                                                                      

)

Aufgrund der Verwendung einer Zeilensperre für die Aktualisierung. Aufgrund der Isolation von Transaktionen muss diese nacheinander ausgeführt werden, damit der obige Code nicht zu Überverkäufen und explodierenden Aufträgen führt. (11 Artikel ausverkauft von 10 Artikeln auf Lager), aber ein solcher Code hat ein Leistungsproblem, das heißt, wie oft

es gleichzeitige Anfragen gibt , wie oft wird an die Datenbank angefordert . Das fragile MySQL brach schnell zusammen.

3 Beenden Sie den Flash-Sale-Code von Redis.


Zuletzt wird der Hauptgang serviert. . . .

//code 3.1   
//用随机值模拟客户,商品,单次购买份数 
       $uid = rand(1,10);
$amount = rand(1,5); 
$goods_id = rand(1,6);
 $time = time(); 

//用redis 校验,此次用户是否可以买。(库存是否充足)
 $redis = self::createRedisObj(); 
$redis_key = "goods_".$goods_id; 
$len = $redis->lLen($redis_key); //求队列的长度,也就是商品的库存。 
if( $len == 0 ){ exit("抢光了!"); }
else if( $len < $amount){ exit("库存不足!"); }

//验证通过,开始pop 出队列。  pop 一个,相当于买一个。  
        for( $i =0 ; $i<  $amount;$i++){
             $redis->rPop( $redis_key );
        }

        $bool = $this->buy($uid , $goods_id , $amount);
        if( !$bool ) {   //如果购买失败,则把取出的redis 队列的数据,再压回去。(回充库存)
         for( $i =0 ; $i<  $amount;$i++){
             $redis->lPush( $redis_key , 1);
         }
     }
//创建redis 对象的。
  private static $_redis = null;
    /**
     * 创建一个redis 对象.
     * @return Redis
     */
    public static function createRedisObj(){ //2017-11-29 改为单例创建模式.

        if( ! self::$_redis){
            $redis = new Redis();
            $host = “192.168.1.xx”;
            $port = "6379";
            $redis->connect($host,$port);
            self::$_redis = $redis;
        }
        return self::$_redis;
    }

Achten Sie auf ein kleines Detail. Normalerweise wird Redis mit dem Framework zum Caching kombiniert. Bitte beachten Sie im obigen Beispiel, dass Sie beim Erstellen des Redis-Objekts eine separate Bibliothek angeben. (Redis hat im Allgemeinen 9 Optionen), um das Löschen der Daten zu vermeiden, wenn der Server den Cache löscht.

Herzlichen Glückwunsch, der obige Code hat eine Basisversion fertiggestellt.

--------------------------------- --- -------------------------------- ---
Das Phänomen wird sich jedoch mit den betrieblichen Anforderungen weiterhin ändern.
Geben Sie mir einfach ein Beispiel.
1 Es wird erwartet, dass das Produkt von einem einzelnen Benutzer nur einmal innerhalb von 3 Sekunden gekauft wird. Keine Produkte

2 Produkte Es besteht die Hoffnung, dass ein einzelner Benutzer bis zu 5 Stück eines einzelnen Produkts kaufen kann.

Wenn diese Situation auftritt


Problem 1 wird wie folgt behandelt

//用随机值模拟客户,商品,单次购买份数 
        $uid = rand(1,10);
        $amount = rand(1,5);
        $goods_id = rand(1,6);
        $time = time();
   
    $redis = self::createRedisObj();
  ////////////单用户限3秒内仅允许请求一次///////////////////////////////
       $lock_key = "uTimeLimit_".$uid;  
      //按用户名编即可。  如果限用户针对指定商品,则lock_key 按uid+ goods_id 进行唯一编码
      if( $redis->get($lock_key)){
            $left_time = $redis->ttl($lock_key);
            exit($expire ."秒内只允许 $tag 一次!请".$left_time."之后再尝试");
        }else {
            $redis->setEx($lock_key ,  $expire , "1" );
        }
//////////////////////////////////////////////////////////////////
//用redis 校验,此次用户是否可以买。(库存是否充足)
  $len = $redis->lLen($redis_key);  //求队列的长度,也就是商品的库存。
        if( $len == 0 ){
            exit("抢光了!");
        }else if( $len < $amount){
            exit("库存不足!");
        }

// Nachkaufprozess. . . . .

Frage 2 wird wie folgt geändert.

//用随机值模拟客户,商品,单次购买份数 
        $uid = rand(1,10);
        $amount = rand(1,5);
        $goods_id = rand(1,6);
        $time = time();
   
    $redis = self::createRedisObj();
  ////////////单用户限5个处理///////////////////////////////
        //设一个hash 表, "user_buy"   然后 $uid . "_" . $goods_id 来记录购买的份数。
    $already_num  =  $redis->hGet("user_buy",$uid."_".$goods_id)? $redis->hGet("user_buy",$uid."_".$goods_id)
:0;  //求出已购买份额
      if( $already_num  +$amount > 5){  exit("单用户单个商品限购买5个");}
      else{ 
            $new_num = $already_num  +$amount ;  
          $redis->hSet("user_buy",$uid."_".$goods_id , $new_num);
    }
////////////////////////////////////////////////////////////////////用redis 校验,此次用户是否可以买。(库存是否充足) 
$len = $redis->lLen($redis_key); //求队列的长度,也就是商品的库存。
 if( $len == 0 ){ exit("抢光了!"); }
else if( $len < $amount){ exit("库存不足!"); }// 后序购买流程。。。。。 
//如果购买失败
    $redis->hSet(
    "user_buy",$uid."_".$goods_id , 
  $redis->hGet("user_buy",$uid."_".$goods_id  ) - $amount  //失败时,则回复hash 表的数值
);

Diese beiden Probleme wurden behoben, und andere ähnliche Probleme können gelöst werden. Aufmerksame Leser können feststellen, dass solche Änderungen etwas gemeinsam haben und der Code zur besseren Wiederverwendung entsprechend gekapselt werden kann.


Verwandte Empfehlungen:

PHP kombiniert mit Redis, um die Anzahl der Besuche durch Benutzer oder IPs innerhalb eines bestimmten Zeitraums zu begrenzen

PHP kombiniert mit dem Linux-Befehl cron, um Beispiele für geplante Aufgaben zu implementieren



Das obige ist der detaillierte Inhalt vonDetaillierte Erklärung von Flash-Sale-Produkten mit PHP in Kombination mit Redis. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Reguläre Ausdrücke in PHPNächster Artikel:Reguläre Ausdrücke in PHP