Php MySQL错误的原因2014无法在其他未缓冲查询处于活动状态时执行查询

Php MySQL错误的原因2014无法在其他未缓冲查询处于活动状态时执行查询,php,mysql,pdo,Php,Mysql,Pdo,我的服务器运行CentOS 6.4,其中MySQL 5.1.69通过yum和CentOS的repos安装,PHP 5.4.16通过yum和ius的repos安装Edit3升级到由IUS社区项目发布的MySQL服务器版本:5.5.31,错误依然存在。然后将库更改为mysqlnd,似乎消除了错误。尽管如此,我们仍然需要知道为什么这个错误只是偶尔出现 使用PDO并使用PDO::ATTR\u EMULATE\u PREPARES=>false创建PDO对象时,有时会出现以下错误: Table Name

我的服务器运行CentOS 6.4,其中MySQL 5.1.69通过yum和CentOS的repos安装,PHP 5.4.16通过yum和ius的repos安装Edit3升级到由IUS社区项目发布的MySQL服务器版本:5.5.31,错误依然存在。然后将库更改为mysqlnd,似乎消除了错误。尽管如此,我们仍然需要知道为什么这个错误只是偶尔出现

使用PDO并使用
PDO::ATTR\u EMULATE\u PREPARES=>false创建PDO对象时,有时会出现以下错误:

Table Name - zipcodes
Error in query:
SELECT id FROM cities WHERE name=? AND states_id=?
SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
File Name: /var/www/initial_install/build_database.php
Line: 547
Time of Error: Tuesday July 2, 2013, 5:52:48 PDT
第547行是以下内容的最后一行:

$stmt_check_county->execute(array($data[5],$data[4]));
if(!$county_id=$stmt_check_county->fetchColumn())
{
    $stmt_counties->execute(array($data[5]));
    $county_id=db::db()->lastInsertId();
}
//$stmt_check_county->closeCursor(); //This will fix the error
$stmt_check_city->execute(array($data[3],$data[4]));
几年前我也遇到过类似的问题,但是从PHP5.1升级到PHP5.3(MySQL可能也更新了),问题神奇地消失了,现在我用PHP5.5解决了

为什么它只有在
PDO::ATTR\u EMULATE\u PREPARES=>false时才会显示出来,并且只有交替版本的PHPs

我还发现
closeCursor()
也会修复错误。在不使用
fetchAll()
的每个
SELECT
查询之后,是否应始终执行此操作?请注意,即使查询类似于只返回一个值的
selectcount(col2)
,仍然会发生错误

编辑顺便说一下,这就是我创建连接的方式。我最近才添加了
MYSQL\u ATTR\u USE\u BUFFERED\u QUERY=>true
,但是,它并不能纠正错误此外,可以按原样使用以下脚本创建错误。

function sql_error($e,$sql=NULL){return('<h1>Error in query:</h1><p>'.$sql.'</p><p>'.$e->getMessage().'</p><p>File Name: '.$e->getFile().' Line: '.$e->getLine().'</p>');}

class db {
    private static $instance = NULL;
    private function __construct() {}   //Make private
    private function __clone(){}   //Make private
    public static function db() //Get instance of DB
    {
        if (!self::$instance)
        {
            //try{self::$instance = new PDO("mysql:host=localhost;dbname=myDB;charset=utf8",'myUsername','myPassword',array(PDO::ATTR_EMULATE_PREPARES=>false,PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC));}
            try{self::$instance = new PDO("mysql:host=localhost;dbname=myDB;charset=utf8",'myUsername','myPassword',array(PDO::ATTR_EMULATE_PREPARES=>false,PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true,PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC));}
            //try{self::$instance = new PDO("mysql:host=localhost;dbname=myDB;charset=utf8",'myUsername','myPassword',array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC));}
            catch(PDOException $e){echo(sql_error($e));}
        }
        return self::$instance;
    }
}

$row=array(
    'zipcodes_id'=>'55555',
    'cities_id'=>123
);
$data=array($row,$row,$row,$row);

$sql = 'CREATE TEMPORARY TABLE temp1(temp_id INT UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (temp_id) )';
db::db()->exec($sql);

$sql='SELECT COUNT(*) AS valid FROM cities_has_zipcodes WHERE cities_id=? AND zipcodes_id=?';
$stmt1 = db::db()->prepare($sql);

$sql ='SELECT temp_id FROM temp1';
$stmt2 = db::db()->prepare($sql);

foreach($data AS $row)
{
    try
    {
        $stmt1->execute(array($row['zipcodes_id'],$row['cities_id']));
        $rs1 = $stmt1->fetch(PDO::FETCH_ASSOC);
        //$stmt1->closeCursor();
        syslog(LOG_INFO,'$rs1: '.print_r($rs1,1).' '.rand());
        $stmt2->execute();
        $rs2 = $stmt2->fetch(PDO::FETCH_ASSOC);
        syslog(LOG_INFO,'$rs2: '.print_r($rs2,1).' '.rand());
    }
    catch(PDOException $e){echo(sql_error($e));}            
}
echo('done');
函数sql\u error($e,$sql=NULL){return('error in query:'.$sql.

'.$e->getMessage()。

文件名:'.$e->getFile()。'Line:'.$e->getLine()。

') db类{ 私有静态$instance=NULL; 私有函数_construct(){}//使私有 私有函数_clone(){}//私有化 公共静态函数db()//获取db的实例 { 如果(!self::$instance) { //试试{self::$instance=new PDO(“mysql:host=localhost;dbname=myDB;charset=utf8”、'myUsername'、'myPassword',array(PDO::ATTR\u EMULATE\u PREPARES=>false,PDO::ATTR\u ERRMODE=>PDO::ERRMODE\u EXCEPTION,PDO::ATTR\u DEFAULT\u FETCH\u MODE=>PDO::FETCH\u ASSOC))} 试试{self::$instance=new PDO(“mysql:host=localhost;dbname=myDB;charset=utf8”、'myUsername'、'myPassword',数组(PDO::ATTR\u EMULATE\u PREPARES=>false,PDO::mysql\u ATTR\u USE\u BUFFERED\u QUERY=>true,PDO::ATTR\u ERRMODE=>PDO::ERRMODE\u异常,PDO::ATTR\u DEFAULT\u FETCH\u MODE=>PDO::FETCH\u ASSOC)} //试试{self::$instance=new PDO(“mysql:host=localhost;dbname=myDB;charset=utf8”、'myUsername'、'myPassword',数组(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC));} catch(pdo异常$e){echo(sql_错误($e));} } 返回self::$instance; } } $row=数组( 'zipcodes_id'=>'55555', “城市标识”=>123 ); $data=数组($row,$row,$row,$row); $sql='创建临时表temp1(temp_id INT UNSIGNED NOT NULL AUTO_INCREMENT,主键(temp_id))'; db::db()->exec($sql); $sql='SELECT COUNT(*)在cities\u中有效,其中cities\u id=?和zipcodes_id=?'; $stmt1=db::db()->prepare($sql); $sql='SELECT temp_id FROM temp1'; $stmt2=db::db()->prepare($sql); foreach($行数据) { 尝试 { $stmt1->execute(数组($row['zipcodes\u id',$row['cities\u id')); $rs1=$stmt1->fetch(PDO::fetch_ASSOC); //$stmt1->closeCursor(); syslog(LOG_INFO,'$rs1:'.print_r($rs1,1)。'.rand()); $stmt2->execute(); $rs2=$stmt2->fetch(PDO::fetch_ASSOC); syslog(LOG_INFO,'$rs2:'.print_r($rs2,1)。'.rand()); } catch(pdo异常$e){echo(sql_错误($e));} } echo(“完成”);
我希望得到比下面更好的答案。虽然其中一些解决方案可能“修复”了问题,但它们并没有回答关于是什么导致了此错误的原始问题

  • Set
    PDO::ATTR\u EMULATE\u PREPARES=>true
    (我不希望这样做)
  • Set
    PDO::MYSQL\u ATTR\u USE\u BUFFERED\u QUERY
    (对我不起作用)
  • 使用
    PDOStatement::fetchAll()
    (并不总是可取的)
  • 每次
    $stmt->closeCursor()
    之后都要使用
    $stmt->fetch()
    (这基本上是有效的,但是,我仍然有几个案例没有这样做)
  • 将PHP MySQL库从PHP MySQL更改为PHP mysqlnd(如果没有更好的答案,我可能会这么做)

  • MySQL客户端协议不允许多个查询“进行中”。也就是说,您已经执行了一个查询,并且已经获取了一些结果,但不是全部——然后您尝试执行第二个查询。如果第一个查询仍有行要返回,则第二个查询将出错

    客户机库通过在第一次获取时隐式获取第一个查询的所有行来解决这个问题,然后后续的获取只是对内部缓存的结果进行迭代。这使他们有机会关闭游标(就MySQL服务器而言)。这是“缓冲查询”。其工作原理与使用fetchAll()相同,因为这两种情况都必须在PHP客户端中分配足够的内存来保存完整的结果集

    不同之处在于,缓冲查询将结果保存在MySQL客户端库中,因此PHP无法访问这些行,直到您按顺序获取()每一行。而fetchAll()会立即为所有结果填充一个PHP数组,允许您访问任意随机行

    不使用fetchAll()的主要原因是结果可能太大,无法满足PHP内存限制。但您的查询结果似乎只有一行,所以这应该不是问题

    在获取最后一行之前,可以关闭游标()以“放弃”结果。MySQL服务器收到通知,它可以在服务器端放弃该结果,然后您可以执行另一个查询。您不应该关闭cursor(),直到
    $sql ='SELECT temp_id FROM temp1';
    $stmt2 = db::db()->prepare($sql);
    $stmt2->execute();
    $rs2 = $stmt2->fetchAll(PDO::FETCH_ASSOC);
    $stmt2->closeCursor();
    
    $sql='SELECT COUNT(*) AS valid FROM cities_has_zipcodes 
          WHERE cities_id=:cities_id AND zipcodes_id=:zipcodes_id';
    $stmt1 = db::db()->prepare($sql);
    
    foreach($data AS $row)
    {
        try
        {
            $stmt1->execute($row);
            $rs1 = $stmt1->fetchAll(PDO::FETCH_ASSOC);
            $stmt1->closeCursor();
            syslog(LOG_INFO,'$rs1: '.print_r($rs1[0],1).' '.rand());
            syslog(LOG_INFO,'$rs2: '.print_r($rs2[0],1).' '.rand());
        }
        catch(PDOException $e){echo(sql_error($e));}            
    }
    
    try { 
        $DBH = new PDO("mysql:host=$hostname;dbname=$db_name", $username, $password, 
        array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET utf8; SET NAMES utf8",
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_NUM));
    } 
    catch(PDOException $e) { echo $e->getMessage(); }
    
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET utf8; SET NAMES utf8"
    
    try { 
        $DBH = new PDO("mysql:host=$hostname;dbname=$db_name", $username, $password, 
        array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_NUM));
    } 
    catch(PDOException $e) { echo $e->getMessage(); }