简单用REDIS实现抢购逻辑
Posted 没文化的人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单用REDIS实现抢购逻辑相关的知识,希望对你有一定的参考价值。
- 创建数据表
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=\'库存\';
- 先将商品库存如队列
<?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\');
?>
- 抢购、描述逻辑
<?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实现抢购逻辑的主要内容,如果未能解决你的问题,请参考以下文章