消息队列可以使用 MySQL 来实现,可以参考博客 PHP 使用 MySQL 实现消息队列 ,虽然用 MySQL 可以实现,但是一般不这么用,因为 MySQL 的数据都存在硬盘中,而从硬盘中对 MySQL 的操作,I/O 花费的代价很大,所以一般使用缓存来实现,因为缓存的数据是在内存中,访问内存的速度远快于访问硬盘的速度.另一方面,Redis 有 list 类型的数据结构,非常适合做消息队列.
这里举一个很简单的秒杀例子:秒杀的名额只有 5 个,即消息队列的长度为 5,名额已经满了之后,通知后来的人已经秒杀结束.然后后台会从消息队列中读取数据,然后将数据存到数据库中.因为消息队列长度只有 5 个,而且秒杀的那短短 1,2 秒并没有直接操作数据库,所以对于数据库来说,并没有什么压力.
先看一下数据库表(seckill)的结构:
然后是进行秒杀的用户程序(user.php), 为了模拟,这里使用 for 循环来实现在短时间内发起大量的请求, 但是要知道这是不准确的.
mysql> desc seckill;
+----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| order_id | int(11) | NO | | NULL | |
| mobile | int(8) | YES | | 8888888 | |
+----------+---------+------+-----+---------+----------------+
3 rows in set (0.11 sec)
运行结果:
<?php
$redis=new Redis();
$redis->connect("127.0.0.1",6379);
$key="seckill";
for($i=0;$i<10;$i++){
$order_id=rand(100000,999999);
$mobile=rand(11111111,99999999);
$value=$order_id."#".$mobile;//连接之后作为值
if($redis->llen("seckill") <5 ){
echo "秒杀成功,订单号为$order_id, 手机号为$mobile\n";
$redis->lpush($key,$value);
} else {
echo "秒杀已经结束\n";
}
}
?>
[root@localhost~]#php user.php秒杀成功,
订单号为643275,
手机号为50104929秒杀成功,
订单号为393012,
手机号为31213041秒杀成功,
订单号为994790,
手机号为23107569秒杀成功,
订单号为186135,
手机号为36549273秒杀成功,
订单号为821972,
手机号为11217760秒杀已经结束秒杀已经结束秒杀已经结束秒杀已经结束秒杀已经结束
然后是后台程序将 redis 中订单读出,处理后存进数据库.
运行:
<?php
$redis=new Redis();
$redis->connect("127.0.0.1",6379);
$pdo=new PDO("mysql:host=localhost;dbname=test","root","root");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt=$pdo->prepare("insert into seckill(id,order_id,mobile) values(?,?,?)");
$key="seckill";
while($redis->llen($key)){
//因为消息队列中添加消息是使用lpush,所以这里使用rpop
$order=$redis->rpop($key);
list($order_id,$mobile)=explode("#",$order);
echo "正在处理订单$order_id\t";
try{
$res=$stmt->execute(array(null,$order_id,$mobile));
if(!$res){
throw new PDOException("wrong");
}
} catch (PDOException $e){
echo $e->getMessage();
echo "订单处理失败\n";
$redis->rpush($key,$order_id."#".$mobile);//将数据恢复达到队列中
continue;
}
echo "订单处理完成\n";
}
?>
[root@localhost ~]# php consumer.php
正在处理订单643275 订单处理完成
正在处理订单393012 订单处理完成
正在处理订单994790 订单处理完成
正在处理订单186135 订单处理完成
正在处理订单821972 订单处理完成
查看数据库:
mysql> select * from seckill;
+----+----------+----------+
| id | order_id | mobile |
+----+----------+----------+
| 1 | 643275 | 50104929 |
| 2 | 393012 | 31213041 |
| 3 | 994790 | 23107569 |
| 4 | 186135 | 36549273 |
| 5 | 821972 | 11217760 |
+----+----------+----------+
5 rows in set (0.00 sec)
来源: http://www.bubuko.com/infodetail-2461502.html