Archive for the ‘事务’ tag
线程安全和一条sql语句引起的思考(一)
这篇文章发布在php分类
因为主要是讨论php的线程安全问题,但是如下遇到的问题在其他的编程环境中也会遇到
首先您肯定会问php官网不是发布过么? 分为线程安全版本和非安全版本
但是既然是线程安全,那言下之意每个进程间相互应该不受干扰.
难道是指所有的进程都需要排队?一个一个的执行
于是抱着问题进行了如下的尝试
<? $host="127.0.0.1"; $user="root"; $passwd="123"; mysql_connect($host,$user,$passwd); mysql_select_db("test"); mysql_query("set names utf8"); //查询是否是大于0的 $res=mysql_query("select * from test where id=1 and k=100"); $res=mysql_fetch_array($res); $money=$res['k']; //如果大于0 就减100 if($money>0){ $res=mysql_query("UPDATE `test` SET `k` = `k`-100 where id=1"); echo "减了!"; }else{ echo "没做操作"; } ?>
代码如上面所示
就是判断k,如果等于100,那么则减去100
数据库test里面只有一个表test
里面的字段为id int k int
只有一条记录
id=1 k=100
好 让我们执行上面的语句
结果一般说来k就会变成0了
但是实际上,问题来了
如果中间的操作耗费了大量的时间,导致延迟更新了
结果又怎样了?
<? $host="127.0.0.1"; $user="root"; $passwd="123"; mysql_connect($host,$user,$passwd); mysql_select_db("test"); mysql_query("set names utf8"); //查询是否是大于0的 $res=mysql_query("select * from test where id=1 and k=100"); $res=mysql_fetch_array($res); $money=$res['k'];
//模拟延迟 这里做一个for循环 模拟中间处理了很多操作
for($i=0;$i<9999999;$i++){
}
//如果大于0 就减100
if($money>0){
$res=mysql_query(“UPDATE `test` SET `k` = `k`-100 where id=1“);
echo “减了!“;
}else{
echo “没做操作“;
}
?>
然后再打开浏览器 重复刷新几次
这个时候结果就不一定是0了! 有可能是-100 –200
视刷新情况而定
而且不管你用所谓的线程安全版本也是同样的结果
为什么么?如果你知道java单例模型中其中的synchronize你应该就明白了
看看这个图
其中左边是线程1 右边是线程2
从上至下假设为我们的线程执行顺序 线程1先执行了
请注意绿色划线部分
线程2得到的$money的值是100!
因为这个时候线程1的update尚未执行
于是当2执行到后面的时候也进行了一次减法
于是就会出现-100 -200的情况
甚至不加for循环,快速刷新一下也会出现这个问题
这说明php的执行并非线程安全,那个所谓的线程安全版本根本就不是这个意思
想来也可以理解,如果真的线程安全了,执行效率很降很多很多很多,因为第二个线程必须等待第一个释放了才能执行
这篇文章先写到这里,下一篇会告诉大家如何解决以及新发生的问题