INFINITY BLUE
msgbartop
ご訪問ありがとうございます。『INFINITY BLUE』は、WEB+DB開発の情報や仕事の実績などを紹介しています。
msgbarbottom

13 3月 08 備忘録:PDOStatement->fetch()をを2回使用する場合

通常設定で下記のようにPDOStatement->fetch()を2回使用すると、エラーとなります。
コード:

dsn = 'mysql:host=接続先;dbname=データベース名'
$user = 'ユーザ名'
$pass = 'パスワード'
$dbh = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => 1));
// エラーが発生した場合、PDOException を投げるように設定
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
// QUERY
$stmt = $dbh->prepare("SELECT * FROM customer ORDER BY id");
$result = $stmt->execute();
while ($rows = $stmt->fetch(PDO::FETCH_ASSOC)) {
// var_dump($rows);
// プリペアドステートメント
$sub_stmt = $dbh->prepare("SELECT * FROM order_summary WHERE id = :id");
// 値をパラメータにバインドする
$sub_stmt->bindParam(":id", $rows["id"]);
// 実行
$result = $sub_stmt->execute();
while ($sub_rows = $sub_stmt->fetch(PDO::FETCH_ASSOC)) {
var_dump($sub_rows);
}
// カーソルを閉じてステートメントを再実行できるようにする
$sub_stmt->closeCursor();
$sub_stmt = null;
}
// カーソルを閉じてステートメントを再実行できるようにする
$stmt->closeCursor();
$stmt = null;
} catch (PDOException $e) {
var_dump($e->getMessage());
}

エラー内容:

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.

回避策は、PDOStatement::fetchAll()を使用するか、PDO::MYSQL_ATTR_USE_BUFFERED_QUERYをtrueの設定にすればよいのですが、
PHPのマニュアル::MySQL 関数 (PDO_MYSQL)では、PDOStatement::fetchAll()を推奨しています。
MySQLでしか利用できない、また他データベースと互換性のない設定だからでしょう。
抜粋:
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY (integer)
PDOStatement でこの属性を TRUE に設定すると、 MySQL ドライバはバッファ版の MySQL API を使用します。 移植性の高いコードを書くには、代わりに PDOStatement::fetchAll() を使用すべきです。

Example#1 mysql でクエリのバッファリングを強制する

< ?php
if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') {
$stmt = $db->prepare('select * from foo',
array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true));
} else {
die("このアプリケーションは mysql でしか動作しません。代わりに \$stmt->fetchAll() を使用すべきです");
}
?>

しかし万件単位のデータを扱い場合PDOStatement::fetchAll()ではメモリオーバーフローしてしまう可能性があります。
そう考えると、PDO->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);の方がよいのか……
SQLのLIMIT句で上手く制御すれば良いだけかもしれませんが……
PHP辞典 第2版 (DESKTOP REFERENCE)Pocket詳解 PHP辞典 (Pocket詳解)PHP辞典 (Desktop reference)



Leave a Comment