PDO无缓冲查询

Jho*_*re- 14 php pdo

我正在尝试进入PDO细节.所以我编码了这个:

$cn = getConnection();

// get table sequence
$comando = "call p_generate_seq('bitacora')";
$id = getValue($cn, $comando);

//$comando = 'INSERT INTO dsa_bitacora (id, estado, fch_creacion) VALUES (?, ?, ?)';
$comando = 'INSERT INTO dsa_bitacora (id, estado, fch_creacion) VALUES (:id, :estado, :fch_creacion)';
$parametros = array (
    ':id'=> (int)$id,
    ':estado'=>1,
    ':fch_creacion'=>date('Y-m-d H:i:s')
);
execWithParameters($cn, $comando, $parametros);
Run Code Online (Sandbox Code Playgroud)

我的getValue函数工作正常,我得到了表的下一个序列.但是当我进入execWithParameters时,我得到了这个异常:

PDOException:SQLSTATE [HY000]:常规错误:2014在其他未缓冲的查询处于活动状态时无法执行查询.考虑使用PDOStatement :: fetchAll().或者,如果您的代码只是针对mysql运行,则可以通过设置PDO :: MYSQL_ATTR_USE_BUFFERED_QUERY属性来启用查询缓冲.在第77行的D:\ Servidor\xampp_1_7_1\htdocs\bitacora\func_db.php中

我试图修改连接属性,但它不起作用.

这些是我的核心数据库功能:

function getConnection() {
    try {
        $cn = new PDO("mysql:host=$host;dbname=$bd", $usuario, $clave, array(
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            ));

        $cn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
        return $cn;
    } catch (PDOException $e) {
        print "Error!: " . $e->getMessage() . "<br/>";
        die();
    }
}
function getValue($cn, $comando) {
    $resul = $cn->query($comando);
        if (!$resul) return null;
        while($res = $resul->fetch()) {
            $retorno = $res[0][0];
            break;
        }
        return $retorno;
}
function execWithParameters($cn, $comando, $parametros) {
    $q = $cn->prepare($comando);
    $q->execute($parametros);
    if ($q->errorInfo() != null) {
        $e = $q->errorInfo();
        echo $e[0].':'.$e[1].':'.$e[2];
    }
}
Run Code Online (Sandbox Code Playgroud)

有人可以为此做点什么?PD.请不要建议做自动数字ID,因为我从另一个系统移植.

Wez*_*ong 22

问题是mysql只允许在给定时间有一个未完成的游标.通过使用fetch()方法而不消耗所有挂起的数据,您将打开游标.

建议的方法是使用fetchAll()方法使用所有数据.另一种方法是使用closeCursor()方法.

如果你改变这个功能,我想你会更快乐:

<?php
function getValue($cn, $comando) {
    $resul = $cn->query($comando);
    if (!$resul) return null;
    foreach ($resul->fetchAll() as $res) {
            $retorno = $res[0];
            break;
    }
    return $retorno;
}
?>
Run Code Online (Sandbox Code Playgroud)


Jon*_*ill 16

如果你没有做一个返回数据的查询(即UPDATE,INSERT等),我认为PDOStatement :: closeCursor()不会起作用.

更好的解决方案是在调用PDOStatement :: execute()之后简单地取消设置()PDOStatement对象:

$stmt = $pdo->prepare('UPDATE users SET active = 1');
$stmt->execute();
unset($stmt);
Run Code Online (Sandbox Code Playgroud)


Tor*_*dek 8

问题似乎是---我对PDO不太熟悉---在你的getValue调用返回后,查询仍然绑定到连接(你只需要第一个值,但连接返回几个,或者希望这样做).

也许getValue可以通过添加来修复

$resul->closeCursor();
Run Code Online (Sandbox Code Playgroud)

在返回之前.

否则,如果对getValue的查询将始终返回单个(或足够少)值,则似乎首选使用fetchAll.


Hen*_*rik 5

我只花了 15 分钟在互联网上谷歌搜索,并查看了至少 5 个不同的 Stackoverflow 问题,其中一些人声称我的 bug 显然是由错误版本的 PHP、错误版本的 MySQL 库或任何其他神奇的黑盒东西引起的......

我将所有代码更改为使用“fetchAll”,甚至在每次查询后对查询对象调用 closeCursor() 和 unset() 。老实说我已经绝望了!我还尝试了 MYSQL_ATTR_USE_BUFFERED_QUERY 标志,但它不起作用。

最后,我把所有的事情都扔到了窗外,查看了 PHP 错误,并跟踪了发生错误的代码行。

SELECT AVG((original_bytes-new_bytes)/original_bytes) as saving 
    FROM (SELECT original_bytes, new_bytes FROM jobs ORDER BY id DESC LIMIT 100) AS t1
Run Code Online (Sandbox Code Playgroud)

不管怎样,问题发生是因为我的original_bytesnew_bytes都是无符号的bigints,这意味着如果我曾经有过一份工作,其中new_bytes实际上比original_bytes大,那么我就会遇到令人讨厌的MySQL“超出范围”错误。这只是在运行我的缩小服务一段时间后随机发生的。

为什么我会得到这个奇怪的 MySQL 错误而不是仅仅给我简单的错误,这超出了我的范围!当我运行原始查询时,它实际上出现在 SQLBuddy(轻量级 PHPMyAdmin)中。我打开了 PDO 异常,所以它应该给我 MySQL 错误。

没关系,底线是:

如果您遇到此错误,请务必检查您的原始 MySQL 是否确实正确并且仍在工作!

  • 刚刚面临这个神秘且无用的错误,多亏了这个答案,我跳出了框框思考了一会儿。事实证明,查询失败的同一连接上的“显示警告”对于调试至关重要。就我而言,错误是:“未知或不正确的时区:‘欧洲/伦敦’”,这是我在创建 PDO 实例时定义的。谢谢@Henrik。 (2认同)