1. 程式人生 > 實用技巧 >PHP+Redis 商品超賣

PHP+Redis 商品超賣

第一種使用Redis LIST做佇列(List的Lpop操作是原子性的)

  • 思路:先在Redis中根據商品數量生成相應的庫存佇列,當用戶搶購商品時先從佇列中獲取商品,然後再進行下單等相關邏輯處理
  • 實踐

    生成庫存佇列

<?php
public function fillStock(){
        $redis = new \Redis();
        $redis->connect("redis",6379);
        $redis->auth("hengda");
        $redis->select(1);
        for
($i = 0;$i < 1000;$i++){ $redis->lPush("shop_list",rand(1000000000,99999999999999)); } }

    搶購消費佇列

<?php
public function purchase(){
        $redis = new \Redis();
        $redis->connect("redis",6379);
        $redis->auth("hengda");
        $redis->select(1);

        
if(!$redis->lPop("shop_list")){ return response_json(1,["msg"=>"已結束"],"success"); } //TODO 生成訂單佇列 }

第二種使用Redis執行Lua指令碼(執行指令碼的eval操作是原子性的)

  • 思路:在redis庫中儲存庫存數,當用戶搶購時先將庫存減1然後再生成訂單對列
  • 實踐
<?php
public function purchaseLua(){
        $redis = new \Redis();
        $redis
->connect("redis",6379); $redis->auth("hengda"); $redis->select(1); $lua_script = <<<LUA local shop_num_exit = redis.call("get","shop_num"); if shop_num_exit == "0" then return false; else return redis.call("decr","shop_num"); end LUA; $result = $redis->eval($lua_script); if($result === false){ return response_json(1,["msg"=>"已結束"],"success"); } //TODO 生成訂單對列 }