13

次のコードがあります。

$dbh = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $dbh->prepare("SELECT 1");
$stmt->execute();
$result = $stmt->fetch();

$stmt->execute();
$result = $stmt->fetch();

$stmt = $dbh->prepare("SELECT 1");
$stmt->execute();
$result = $stmt->fetch();

ただし、何らかの理由で、2 番目の準備済みステートメントを実行すると、次のエラーが発生します。

致命的なエラー: キャッチされない例外 'PDOException' とメッセージ 'SQLSTATE[HY000]: 一般エラー: 2014 他のバッファリングされていないクエリがアクティブな間はクエリを実行できません。PDOStatement::fetchAll() の使用を検討してください。または、コードが mysql に対してのみ実行される場合は、PDO::MYSQL_ATTR_USE_BUFFERED_QUERY 属性を設定して、クエリのバッファリングを有効にすることができます。

私はこのエラーが何を意味し、それをどのように修正するかを知っています (実行するか、unset($stmt);または実行$stmt->closeCursor();します)。私が理解していることから、それは通常、すべての結果を取得するfetch代わりに行うことによって引き起こされます。fetchAllただし、この場合、結果は 1 つしかなく、フェッチされています。また、最初の準備済みステートメントを 1 回だけ実行すると、エラーは発生しません。最初のステートメントが2 回実行された場合にのみ発生します。また、 が の場合にのみ発生しPDO::ATTR_EMULATE_PREPARESますfalse

私の質問は、この場合に上記のエラーが発生する原因は何ですか? これまでに実行した他のクエリと何ら変わりはないようです。

Debian と CentOS の 2 つの Ubuntu 13.10 サーバーでこれをテストしましたが、デフォルトのパッケージを使用するとすべて同じエラーが発生します。

編集:

Ryan Vincent のコメントに答えるために、私は完全な mysqli 初心者ですが、以下にあるものは上記の例とほぼ同等であると信じています。私が間違っている場合は、私を修正してください。ただし、エラーは発生しないため、PDO のみのエラーのように見えます。

$mysqli = new mysqli($host, $user, $pass, $dbname);
if ($mysqli->connect_errno) {
    die("Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error);
}

if (!($stmt = $mysqli->prepare("SELECT 1"))) {
     die("Prepare 1 failed: (" . $mysqli->errno . ") " . $mysqli->error);
}

if (!$stmt->execute()) {
    die("Execute 1 failed: (" . $stmt->errno . ") " . $stmt->error);
}
$stmt->store_result();
$stmt->bind_result($col1);
$stmt->fetch();

if (!$stmt->execute()) {
    die("Execute 2 failed: (" . $stmt->errno . ") " . $stmt->error);
}
$stmt->store_result();
$stmt->bind_result($col1);
$stmt->fetch();

if (!($stmt = $mysqli->prepare("SELECT 1"))) {
    // The following line is what fails in PDO
    die("Prepare 2 failed: (" . $mysqli->errno . ") " . $mysqli->error);
}

if (!$stmt->execute()) {
    die("Execute 3 failed: (" . $stmt->errno . ") " . $stmt->error);
}
$stmt->store_result();
$stmt->bind_result($col1);
$stmt->fetch();
4

4 に答える 4

13

奇妙なことに、Ubuntu が提供する PHP パッケージはMysqlネイティブ ドライバーでコンパイルされず、代わりに古いlibmysqlclientでコンパイルされます (デフォルト パッケージを使用して Ubuntu 13.10 でテスト済み)。

<?php
echo $dbh->getAttribute(PDO::ATTR_CLIENT_VERSION); // prints "5.5.35", i.e MySQL version
// prints "mysqlnd (...)" when using mysqlnd

あなたのまさにテストケース ("Edit 4", with setAttribute(MYSQL_ATTR_USE_BUFFERED_QUERY, true)) は、mysqlnd で手動でコンパイルされた PHP 5.5.3 で期待どおりに動作します:

./configure --with-pdo-mysql=mysqlnd # default driver since PHP v5.4

...しかし、失敗します:

bash> ./configure --with-pdo-mysql=/usr/bin/mysql_config

最初のステートメントが 2 回実行された場合にのみ失敗するのは非常に奇妙です。これは、 libmysqlclientドライバーのバグに違いありません。

が の場合、両方のドライバーが予期したとおりに失敗しMYSQL_ATTR_USE_BUFFERED_QUERYますfalseあなたの常識は、結果セットの行数に関係なく、これが予期される動作である理由をすでに示しています。

Mike は、現在の回避策がphp5-mysqlndCanonical-recommended の代わりにパッケージをインストールすることであることを発見しましたphp5-mysql

于 2014-04-07T06:37:26.553 に答える
3

これは必ずしもこの質問に対する答えではありませんが、これは将来誰かを助けるかもしれません.

まったく同じエラーに遭遇し、何が問題なのかを発見するのに何時間もかかりました. それはずっと、非常にマイナーな構文の問題であることが判明しました。実際にバッファリングを使用していないのに、私のようにこのエラーが発生する場合は、これが問題である可能性があります。コードを確認してください。

このエラーに遭遇したとき、私は通常のデータベース クエリを実行していました (意図的にバッファリング技術を使用していません)。私はそれに関するすべてのSOの質問を読み、それをより深く調べました.

これは私の STUPID 構文の問題でした:

$SQL = "UPDATE articles SET
            topicID = :topic;    <-------- semicolon - woops!
            heading = :heading,
            subheading = :subheading,
            keywords = :keywords,
            rawContent = :rawContent,
            content = :content,
            ...
            ...

これにより、このバッファリングエラーが発生しました。コードを修正したところ、消えました。最も厄介だったのは、PDO エラーが別のクエリ、次のクエリを指していたという事実でしたが、そのクエリはコード内の別の場所にある関数にあり、それはしばらくコースから外れていました!

于 2014-08-11T22:50:56.483 に答える