目录
- 概述
- 应用场景
- 不使用事务的时候并发问题
- 使用mysql事务和锁解决并发商品超卖问题
- php7进阶到架构师相关阅读
概述
这是关于php进阶到架构之 PHP核心技术与实践 系列学习课程:PHP利用MYSQL锁解决高并发超卖问题
学习目标 :
解决类似商城秒杀高并发导致库存变成负数的问题
应用场景
在商城秒杀应用中,高并发时,在没有事务的时候,商品会出现超卖的情况,即商品的库存出现负数的情况
创建库存管理表
创建订单管理表
CREATE TABLE order (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
number int(11) DEFAULT NULL,
PRIMARY KEY ( id )
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=latin1
不使用事务的时候并发问题
测试代码
$pdo = new PDO('mysql:host=127.0.0.1;port=3306; dbname=test','root','123456');
$sql="select `number` from storage where id=1 limit 1";
$res = $pdo->query($sql)->fetch();
$number = $res['number'];
if($number>0)
{
$sql ="insert into `order` VALUES (null,$number)";
$order_id = $pdo->query($sql);
if($order_id)
{
$sql="update storage set `number`=`number`-1 WHERE id=1";
$pdo->query($sql);
}
}
我们预置库存是十个,然后执行ab测试查看结果
mysql> select * from storage
-> ;
+—-+——–+
| id | number |
+—-+——–+
| 1 | -2 |
+—-+——–+
1 row in set (0.00 sec)
库存数变成了-2,变成了负数,即出现了超卖现象
使用mysql事务和锁解决并发商品超卖问题
代码调整如下
$pdo = new PDO('mysql:host=127.0.0.1;port=3306; dbname=test','root','123456');
$pdo->beginTransaction();//开启事务
$sql="select number from storage where id=1 for UPDATE ";//利用for update 开启行锁
$res = $pdo->query($sql)->fetch();
$number = $res['number'];
if($number>0)
{
$sql ="insert into order VALUES (null,$number)";
$order_id = $pdo->query($sql);
if($order_id)
{
$sql="update storage set `number`=`number`-1 WHERE id=1";
if($pdo->query($sql))
{
$pdo->commit();//提交事务
}
else
{
$pdo->rollBack();//回滚
}
}
else
{
$pdo->rollBack();//回滚
}
}
例如ab模拟并发测试之后,查看结果如下:
mysql> select * from storage;
+----+--------+
| id | number |
+----+--------+
| 1 | 0 |
+----+------
--+
1 row in set (0.00 sec)
利用mysql锁以后,库存数没有变成负数,即没有出现商品超卖的情况
php7进阶到架构师相关阅读
最后,欢迎大家留言补充,讨论~~~
喜欢小编的话,欢迎点赞、收藏和关注哦~~~///(^v^)\\\~~~
海报
0 条评论
218
相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~