PHP combined with redis seconds to kill the product of the detailed

Source: Internet
Author: User
Tags yii

This article mainly introduces the PHP combined with redis seconds to kill the product of the detailed, has a certain reference value, now share to everyone, the need for friends can refer to

1 First, a little bit of prep work.

1.1 Create a commodity table, order form , and initialize the data

Order form.


1.2 Write the commodity data to the Redis queue.

For example, number 1 merchandise has 100 pieces. Just go to the goods_1 queue and write 100 1 in. Example with a pop operation Atomic (carry concurrency) after purchase, buy one on the pop one.

The code uses the YII framework, focusing on ideas and other frameworks to make minor adjustments.  $redis = Self::createredisobj ();//Create a Redis object followed by detailed code        $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;

As soon as it is built. (in real case, the background may appear in the library adjustment, the corresponding to synchronize the data in the Redis, the actual project please note, this is not a table)

2 No Redis, the regular purchase code.

Simulate customer, commodity, single purchase number $uid = rand (1,10) with random value;        $amount = rand (1,5);        $goods _id = rand (1,6);        $time = time (); $this->buy ($uid, $goods _id, $amount);p ublic function Buy ($uid, $goods _id, $amount) {//Use row locks.            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) {//share sufficient. $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 ("Execution failed". $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 ("Execution failed". $sql);}            } $trans->commit ();        return true;            } catch (Exception $e) {//log record $trans->rollback ();        return false; }}

Then use the Apache AB gadget to test.
-N represents the number of requests-C represents a single concurrent request.

Ab-n 1000-c http://xxx

(The above code to remove the transaction, and then AB Run will appear a single, oversold problem details click)

Because row lock for update is used. Transaction-based isolation, must be sequential execution, so the above code, there will be no oversold single problem. (10 sold in stock 11 pieces), but there is a performance problem with this code, that is, how many concurrent requests, how many times will the database be requested. The fragile MySQL was soon blown away.

3-knot Redis's Seconds kill code.

Finally on the right dish ....

Code 3.1//Use random value to simulate customer, commodity, number of purchases per purchase $uid = rand (1,10); $amount = rand (1,5); $goods _id = rand (1,6); $time = time (); With Redis check, whether this user can buy. (Adequacy of inventory) $redis = Self::createredisobj (); $redis _key = "Goods_". $goods _id; $len = $redis->llen ($redis _key); The length of the queue, i.e. the inventory of the goods. if ($len = = 0) {exit ("robbed!");} else if ($len < $amount) {exit ("insufficient stock!");}  The validation passes and the pop out queue starts.          Pop one, the equivalent of buying one.        for ($i =0; $i < $amount; $i + +) {$redis->rpop ($redis _key);        } $bool = $this->buy ($uid, $goods _id, $amount); if (! $bool) {//If the purchase fails, the data from the Redis queue is removed and then pressed back.         (Recharge stock) for ($i =0; $i < $amount; $i + +) {$redis->lpush ($redis _key, 1);  }}//to create a Redis object.    private static $_redis = null;     /** * Create a Redis object.        * @return Redis */public static function Createredisobj () {//2017-11-29 changed to singleton creation mode.            if (! Self::$_redis) {$redis = new Redis ();            $host = "192.168.1.xx";    $port = "6379";        $redis->connect ($host, $port);        Self::$_redis = $redis;    } return Self::$_redis; }

Note A small detail, usually redis will be cached in conjunction with the framework. In the example above, note that when you create a Redis object, you specify a separate library. (Redis typically has 9 optional) to avoid emptying the data when the server clears the cache.

To this, the code above completes a basic version.
------------------------------------------------------------------------------------------------
However, in the phenomenon, it will change with the operation demand constantly.
Give me an example.
1 Products I hope the single user can only buy one time in 3 seconds. No product

2 products you want to buy up to 5 items per individual item.

In this situation

Issue 1 is handled as follows

Simulate customer, commodity, single purchase number         $uid = rand (1,10) with random value;        $amount = rand (1,5);        $goods _id = rand (1,6);        $time = time ();       $redis = Self::createredisobj ();  Only one///////////////////////////////       $lock _key = "Utimelimit_" is allowed in a single user limit of 3 seconds. $uid;        You can edit by user name.  If the user is limited to a specified product, the Lock_key is uniquely encoded by uid+ goods_id      if ($redis->get ($lock _key)) {            $left _time = $redis TTL ($lock _key);            Exit ($expire. " Only allow $tag once in seconds! ". $left _time." Then try again ");        } else {            $redis->setex ($lock _key,  $expire, "1");        } With Redis check, whether this user can buy. (Adequacy of inventory)  $len = $redis->llen ($redis _key);  The length of the queue, i.e. the inventory of the goods.        if ($len = = 0) {            exit ("Robbed!");        } else if ($len < $amount) {            exit ("Insufficient stock!");        }

Order purchase process .....

Issue 2 is modified as follows.

Simulate customer, commodity, single purchase number $uid = rand (1,10) with random value;        $amount = rand (1,5);        $goods _id = rand (1,6);       $time = time ();  $redis = Self::createredisobj (); Single user limit of 5 processing/////////////////////////////////Set a hash table, "User_buy" and then $uid. "_" .    $goods _id to record the number of copies purchased. $already _num = $redis->hget ("User_buy", $uid. " _ ". $goods _id)? $redis->hget ("User_buy", $uid. "  _ ". $goods _id): 0;      Find out the purchased shares if ($already _num + $amount > 5) {exit ("single-user single item purchase limit of 5");}            else{$new _num = $already _num + $amount; $redis->hset ("User_buy", $uid. "    _ ". $goods _id, $new _num); }////////////////////////////////////////////////////////////////////with Redis Check, whether this user can buy. (Adequacy of inventory) $len = $redis->llen ($redis _key); The length of the queue, i.e. the inventory of the goods. if ($len = = 0) {exit ("robbed!");} else if ($len < $amount) {exit ("insufficient stock!");} Order purchase process ..... If the purchase fails $redis->hset ("User_buy", $uid. " _ ". $goods _id, $redis->hget (" User_buy ", $uid." _ ". $goods _id)-When $amount//failure, the reply hash Value of the table); 

These two problems have been dealt with, and other similar problems are found in the recruit. A mind reader can find that such modifications have something in common, and that they can be properly encapsulated in code and reused better.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.