简单用REDIS实现抢购逻辑

Posted 没文化的人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单用REDIS实现抢购逻辑相关的知识,希望对你有一定的参考价值。

  1. 创建数据表

 

 

SET FOREIGN_KEY_CHECKS=0;

 

-- ----------------------------

-- Table structure for ih_goods

-- ----------------------------

DROP TABLE IF EXISTS `ih_goods`;

CREATE TABLE `ih_goods` (

  `goods_id` int(10) unsigned NOT NULL AUTO_INCREMENT,

  `cat_id` int(11) NOT NULL,

  `goods_name` varchar(255) NOT NULL,

  PRIMARY KEY (`goods_id`)

) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

 

-- ----------------------------

-- Records of ih_goods

-- ----------------------------

INSERT INTO `ih_goods` VALUES (\'1\', \'0\', \'小米手机\');

 

-- ----------------------------

-- Table structure for ih_log

-- ----------------------------

DROP TABLE IF EXISTS `ih_log`;

CREATE TABLE `ih_log` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `event` varchar(255) NOT NULL,

  `type` tinyint(4) NOT NULL DEFAULT \'0\',

  `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

  PRIMARY KEY (`id`)

) ENGINE=MyISAM DEFAULT CHARSET=utf8;

 

-- ----------------------------

-- Records of ih_log

-- ----------------------------

 

-- ----------------------------

-- Table structure for ih_order

-- ----------------------------

DROP TABLE IF EXISTS `ih_order`;

CREATE TABLE `ih_order` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `order_sn` char(32) NOT NULL,

  `user_id` int(11) NOT NULL,

  `status` int(11) NOT NULL DEFAULT \'0\',

  `goods_id` int(11) NOT NULL DEFAULT \'0\',

  `sku_id` int(11) NOT NULL DEFAULT \'0\',

  `price` float NOT NULL,

  `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=3697 DEFAULT CHARSET=utf8 COMMENT=\'订单表\';

 

-- ----------------------------

-- Records of ih_order

-- ----------------------------

 

-- ----------------------------

-- Table structure for ih_store

-- ----------------------------

DROP TABLE IF EXISTS `ih_store`;

CREATE TABLE `ih_store` (

  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,

  `goods_id` int(11) NOT NULL,

  `sku_id` int(10) NOT NULL DEFAULT \'0\',

  `number` int(11) unsigned NOT NULL DEFAULT \'0\',

  `freez` int(11) NOT NULL DEFAULT \'0\' COMMENT \'虚拟库存\',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT=\'库存\';

 

  1. 先将商品库存如队列

 

    <?php  
    $store=1000;  
    $redis=new Redis();  
    $result=$redis->connect(\'127.0.0.1\',6379);  
    $res=$redis->llen(\'goods_store\');  
    echo $res;  
    $count=$store-$res;  
    for($i=0;$i<$count;$i++){  
        $redis->lpush(\'goods_store\',1);  
    }  
    echo $redis->llen(\'goods_store\');  
    ?> 

  1. 抢购、描述逻辑

 

<?php

 

 

     /**

  *   数据库封装

  */

    class PDORepository{

        const USERNAME="root";

        const PASSWORD="@liu416115";

        const HOST="47.93.33.115";

        const DB="my";

 

        private function getConnection(){

            $username = self::USERNAME;

            $password = self::PASSWORD;

            $host = self::HOST;

            $db = self::DB;

            $connection = new PDO("mysql:dbname=$db;host=$host",$username,$password);

            return $connection;

        }

        public function queryList($sql, $args){

            $connection = $this->getConnection();

            $stmt = $connection->prepare($sql);

            $stmt->execute($args);

            return $stmt;

        }

    }

 

 

/**

 * 封装的REDIS  可以自己修改

 */

 

class RedisClass

{

 

public $resuorce ;

 

public function __construct()

{

$this->resuorce=new Redis();

}

 

public function connect()

{

$this->resuorce->connect(\'47.93.33.115\',6379);

}

 

public  function lpush($key,$value)

{

return $this->resuorce->lpush($key,$value);

}

 

public function rbpop($key)

{

return $this->resuorce->rpop($key);

}

 

public function lpop($key)

{

return $this->resuorce->lpop($key);

}

 

public function  llen($key){

  return  $this->resuorce->llen($key);

}

 

public function rpoplpush($reurce_key,$dest_key)

{

return $this->resuorce->rpoplpush($reurce_key,$dest_key);

}

 

public function delete($keys)

{

return $this->resuorce->del($keys);

}

}

 

 

  

    $redis = new RedisClass();

    $redis->connect(\'47.93.33.115\',6379);

    $count=$redis->lpop(\'goods_store\');

 

    if(!$count){

       insertLog(\' 以抢光\');

       return;

    }

$user_name = time();

$result = $redis->lpush(\'user_store\',$user_name);

if(!$result) {

  insertLog(\' 抢购失败\');

       return;

} else {

echo "抢购成功";

}

 

 

$price=10;

$goods_id=1;

$sku_id=11;

$number=1;

 

// 抢购成功保存到数据库

$user_id = $redis->rbpop(\'user_store\');

$redis->lpush(\'used_user_store\',$user_id);

$order_sn=build_order_no();

$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price) values(\'$order_sn\',\'$user_id\',\'$goods_id\',\'$sku_id\',\'$price\') ";

 

$rep = new PDORepository();

$rep->queryList($sql,array());

 

$sql="update ih_store set number=number-($number) where sku_id=\'$sku_id\'";

$result = $rep->queryList($sql,array());

 

if($result){

    insertLog(\'inc\');

}else {

    insertLog(\'dec\');

}

 

 

 

function build_order_no(){

 return date(\'ymd\').rand()*100;

}

 

 

function insertLog($event,$type=0){

 

 $sql="insert into ih_log(:event,:type) values(\'$event\',\'$type\')";

  $rep = new PDORepository();

  $rep->queryList($sql,array(\':event\'=>$event,\':type\'=>$type));

 

}

 

模拟5000高并发测试

 

//ab -r -n 6000 -c 5000  http://47.93.33.115/qiang.php

 

 

总结:使用redis队列,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用(mysql事务在高并发下性能下降很厉害,文件锁的方式也是) 有不足的地方望指正

 

欢迎关注

以上是关于简单用REDIS实现抢购逻辑的主要内容,如果未能解决你的问题,请参考以下文章

Redis解决秒杀微服务抢购代金券超卖和同一个用户多次抢购

redis实现高并发下的抢购/秒杀功能

php结合redis实现高并发下的抢购秒杀功能

PHP和Redis实现在高并发下的抢购及秒杀功能示例详解

php+redis实现简单秒杀抢购功能

简单实现redis实现高并发下的抢购/秒杀功能(转)