ホームページ >バックエンド開発 >PHPチュートリアル >PHPとredisを組み合わせたフラッシュセール商品の詳細説明
orderテーブルのデータを初期化します。
1.2 製品データを Redis キューに書き込みます。
例えば、商品No.1は100個あります。 100 個の 1 を Goods_1 キューに書き込むだけです。たとえば、ポップ操作の原子性 (同時実行性の保持) を使用して、後で購入する場合は、1 つ購入した後に 1 つポップするだけです。
//代码使用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;
完成後は以下の通り。 (実際の状況では、バックグラウンドでライブラリの調整が行われる可能性があり、それに応じて Redis 内のデータを同期する必要があります。実際のプロジェクトでは注意してください。現時点ではここには示されていません)
(上記のコードのトランザクションを削除すると、AB が実行されると爆発的な注文が発生します。時間外問題の詳細をクリックしてください。 トランザクションの分離に基づいて、トランザクションは順次実行される必要があるため、上記のコードは過剰販売や注文の爆発を引き起こすことはありません。 (在庫 10 個のうち 11 個が売り切れました) しかし、このコードにはパフォーマンスの問題があります。つまり、
同時リクエストが何回あるか、データベース
に何回
3 Redisのフラッシュセールコードを終了します。 いよいよメイン料理の提供です。 。 。 。
//用随机值模拟客户,商品,单次购买份数 $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 = '$sn',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; } }
通常、redis はキャッシュ用のフレームワークと結合されます。上記の例では、redis オブジェクトを作成するときに別のライブラリを指定することに注意してください。 (redis には通常 9 つのオプションがあります) サーバーがキャッシュをクリアするときにデータがクリアされないようにします。 おめでとうございます。上記のコードで基本バージョンが完成しました。
------------------------------------------------- --------------------------------------------------2 商品 1 人のユーザーが 1 つの商品を最大 5 個まで購入できることを希望します。
この状況に遭遇した場合
問題 1 は次のように処理されます
//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; }
質問2は次のように修正されます。
//用随机值模拟客户,商品,单次购买份数 $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("库存不足!"); }
これら 2 つの問題はすでに解決されており、他の同様の問題もできるだけ早く解決される予定です。注意深い読者であれば、このような変更には共通点があり、再利用しやすくするためにコードを適切にカプセル化できることがわかります。
関連する推奨事項:
PHP を Redis と組み合わせて、一定期間内のユーザーまたは IP によるアクセス数を制限する
PHP を Linux cron コマンドと組み合わせて、スケジュールされたタスクの例を実装する
以上がPHPとredisを組み合わせたフラッシュセール商品の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。