手机访问          
logo
php 处理高并发时 锁 mysql SELECT .. FOR UPDATE
更新时间: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 的数据加锁,然后更新这条数据后提交,才解锁。下一个会话只能等这个会话解锁后,才能进行查询操作,进而更新解锁 。


当然,这些程序要在事务内部进行才正常




分享按钮 分类:php
  

create:2016-07-19    阅读量(5812) 评论( 0 )

返回顶部
登录评论
  ABOUT ME
头像
昵称零零一
博龄 { 58.5月 }
积分610
博主被推荐的文章
相关博文
推荐博文
    诊断学重点知识汇总!医学生必备
    当遇见一个自己在意的人或事物时,这时人们
    ​isnull函数
    疾病及编码介绍十三、起源于围生期的某些情
    无法在System.int32和Syst
    truacate table 与dele
    “男孩子一个人在外,要好好保护自己”
    事务的特性
    Logstash启动报错
    C#键盘输入回车键实现点击按钮效果的方法
标签云
反馈 联系©2015-2016 2016 ©zhoubo15.cn 粤ICP备15029033号-1