上个月稀里糊涂的犯了两次差不多的问题.....特记下,以示警醒。
第一次:悲催的改了三次代码...
根据特定条件,打印curl语句,然后放到 .sh文件中,用Shell来执行。
查询表***,根据产品id和结束时间(大于当前时间)查询用户。通过接口执行特定语句(就是我打印出来的语句)。
第一次代码:
$config = array(
array(1,2,3,4),
array(5,6,7,8)
);
foreach ($config as $item) {
$sql = "select * from (select userid,enddate from tablename where id in (?,?,?) and enddate > now() order by enddate desc) as a group by userid";
$sth = DB_Pdo::instance()->get_dbh()->prepare($sql);
$sth->execute(array($item[0],$item[1],$item[1]));
$arr = $sth->fetchAll(PDO::FETCH_ASSOC))
$sth = null;
foreach ($arr as $value) {
echo "curl '链接(此处省略)&sid=".$item[3]."&enddate=".$value['enddate']."&userid=".$value['userid']."'\n";
}
}
这个代码在代码层面是没问题的,但是当数据量比较大的时候就会出现问题了,嵌套的sql语句执行起来很耗费时间、资源,可能会导致宕机。因此废弃,换一种方式。 ......... 悲剧即将到来。
第二次代码:
$config = array(
array(1,2,3,4),
array(5,6,7,8)
);
$userid_arr = array();
foreach ($config as $item) {
$sql = "select userid,enddate from tablename where id in (?,?,?) and enddate > now() order by id";
$sth = DB_Pdo::instance()->get_dbh()->prepare($sql);
$sth->execute(array($item[0],$item[1],$item[1]));
while (false !== $row = $sth->fetch(PDO::FETCH_ASSOC)) {
if($userid_arr[$row['userid']] < $row['enddate']){
$userid_arr[$row['userid']] = $row['enddate'];
}
}
$sth = null;
foreach ($userid_arr as $key => $value) {
echo "curl '链接(此处省略)&sid=".$item[3]."&enddate=".$value."&userid=".$key."'\n";
}
}
上边代码,改了sql语句,但是用到了循环。。。大眼一看,好像没问题,但是当运行的时候就会发现,curl语句比第一次代码执行出来的要多一部分。然后才发现循环语句中的 $userid_arr 是在foreach外面声明的,也就是说foreach循环第二次的时候$userid_arr数组内依然包含第一次循环后的结果,此时并不是空数组......然后第二次foreach的时候会把第一次循环过的数据再次循环。。。
所以又改了第三次,将$userid_arr = array(); 移到while上面,这样每次foreach的时候都会执行 userid_arr = array()
做循环的时候,遇到数组要么在之前声明,要么就在底部销毁。。。切记切记。。。然鹅。峩还是莫记得......不过这次是变量,不是数组了.........
第二次犯的错误和第一次类似
脚本代码大体上就是这样(代码过长,就缩略一下)
while(1){
$result = 从队列取出来的数据;
if(! $result){
echo "*";
sleep(1);
}elseif($result){
处理 $result 数据;
*
*
*
*
*一大堆代码(省略)···
if(isset($result['appflag']) && isset($result['appid'])){
$appflag = $result['appflag'];
$appid = $result['appid'];
}
*
*
*
*
*又一大堆代码(省略)···
if($appflag && $appid){
危险代码........
}
}
}
$result 是从kafka取出来的数组,但是数据还不一样,有些包含了 $result['appflag'] 和 $result['appid']。。 有些数组则没有这两项。这就是噩梦的开端,执行了之后,发现。。。唉~~~ 没有包含$result['appflag'] 和 $result['appid']的数据,也执行了“危险代码”。仔细检查发现:if($appflag && $appid) 并未生效,看了下发现是while循环,当运行了一次包含了 $result['appflag'] 和 $result['appid']的数据后,$appflag 、 $appid 这两个变量就一直存在了.....再循环的时候 $appflag && $appid 就一直为true了,代码也就一直执行了。
代码长并不是未声明$appflag 和 $appid 的借口,幸好及时发现,在执行完“危险代码”后,增加销毁$appflag 、 $appid 两个变量的代码,直接unset掉。。。或者代码中一直使用$result['appflag'],$result['appid'] 不做赋值操作,也不会出现这种问题。
总之总之,循环操作一定要倍加小心,用到数组要声明,用到循环内用到判断一定要仔细看下条件是否需要做处理。。。
切记,以上。