更新时间:2016-07-19 13:07:04
5812次阅读
评论
0
php高并发处理方面的知识较少。
高并发时,需要考虑高并发的状况:资源调用与实际可调用的资源不一致,到时候就尴尬了
说个场景:果农卖苹果,箩筐里刚好有3个苹果并只能最多放3个苹果,这时候,有四个人都付了一个苹果的钱,都准备挑一个苹果看看,结果只有3个人拿到了苹果,另外一个付了钱没拿到苹果的人暂时没有拿到苹果,果农如果能够从仓库里面调出苹果,把苹果放到箩筐里面,继续让付了钱没拿到苹果的人挑苹果。如果没有苹果,抱歉只能退款--尴尬了
这就是消费者,生产者,库存的关系
网站访问时,如果是大网站,经常出现高并发访问的情况,如果高并发获取资源,这需要处理生产者,消费者以及库存的关系了
建立一张库存表
CREATE TABLE `dede_test_stock` ( `id` int(11) NOT NULL AUTO_INCREMENT, `num` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
然后,把网站当成生产者
$db->Query("start transaction");//开启事务 $db->Query("set autocommit = 0"); // 设置禁止提交 //$db->Query("begin"); $sql = "SELECT * FROM dede_test_stock WHERE id = 1 FOR UPDATE"; $db->Query($sql); $result = $db->fetchRow(); var_dump($result); if($result["num"]>0){// 库存大于零可以取,每次取一个 $sql = "set autocommit = 1"; // 设置允许提交 $db->Query($sql); $sql = "update dede_test_stock set num = (num-1)"; $db->Query($sql); $db->Query("commit"); echo "减库存"; }else{ $sql = "set autocommit = 1"; $db->Query($sql); $sql = "update dede_test_stock set num = num"; $db->Query($sql); $db->Query("commit"); echo "不减库存"; }
结果在高并发执行时,有时会出现负值的库存
上面的程序有bug吧,下面改改程序
$db->Query("start transaction");//开启事务 $db->Query("set autocommit = 0"); // 设置禁止提交 //$db->Query("begin"); $sql = "SELECT * FROM dede_test_stock WHERE id = 1 FOR UPDATE"; $db->Query($sql); $result = $db->fetchRow(); var_dump($result); if($result["num"]>0){// 库存大于零可以取,每次取一个 $sql = "update dede_test_stock set num = (num-1)"; $db->Query($sql); $sql = "set autocommit = 1"; // 设置允许提交 $db->Query($sql); $db->Query("commit"); echo "减库存"; }else{ $sql = "update dede_test_stock set num = num"; $db->Query($sql); $sql = "set autocommit = 1"; $db->Query($sql); $db->Query("commit"); echo "不减库存"; }
结果,再也没有出现负值的库存了
说一下为什么会这样?
在上面的sql语句肯定有锁在作用吧
高并发时,有多个会话访问数据库表记录,这时候需要选择一个会话在拿资源时上锁,拿完资源解锁,然后让下一个会话进来,然后上锁,拿完解锁..没有资源没得拿 如此就不会出现库存负值时,显示可以拿的情况了
select .. for update 语句后,会对select 的数据加锁,然后更新这条数据后提交,才解锁。下一个会话只能等这个会话解锁后,才能进行查询操作,进而更新解锁 。
当然,这些程序要在事务内部进行才正常
create:2016-07-19
阅读量(5812)
评论(
0
)