LoginSignup
8
6

More than 5 years have passed since last update.

PHP: PDOStatement::fetchは途中でMySQLサーバが落ちたとしても静かに処理を中断してしまう

Posted at

PHPのPDOStatementはfetchしているループの最中に、MySQLサーバがシャットダウンしたりして結果セットがすべて取れなくなっても、例外を投げたり、エラーを出したりはせずに静かに処理を中断してしまうようだ。

検証コード:

<?php

$pdo = new PDO(
    'mysql:dbname=testing;host=localhost',
    'root',
    'root',
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false,
    ]
);

// ダミーデータを1024件(64MBほど)作る
$pdo->query('CREATE TABLE IF NOT EXISTS data (data text)');
//$pdo->query('TRUNCATE TABLE data');
$stmt = $pdo->query('SELECT COUNT(*) AS total FROM data');
if ($stmt->fetch()['total'] == 0) {
    $stmt = $pdo->prepare('INSERT INTO data VALUES (?)');
    for ($i = 0; $i < 1024; $i++) {
        $stmt->execute([str_repeat('a', (1024 * 64) - 1)]); // 64KB - 1
    }
}

unset($stmt);

// メモリが少なくなってる状況を作り、すべての結果セットがメモリに乗らないようにする
ini_set('memory_limit', '2M');

$statement = $pdo->query('SELECT * FROM data');
$i = 1;
while ($row = $statement->fetch()) {
    echo $i++, PHP_EOL;
    usleep(100000); // このループ中にMySQLサーバを落としてみる
}
var_dump($row);
var_dump($statement->errorInfo());

PDOStatement::fetch()している最中に、MySQLサーバを落としてみる:

$ brew services start mysql
==> Successfully started `mysql` (label: homebrew.mxcl.mysql)

すると読み込めた行まででループが終了する。下の結果例では77行目まで読み込めたが、残りの947行は当然読み取られない。

出力結果:

71
72
73
74
75
76
77
/private/var/folders/mf/cm46yj755lv9v_v4458953lc0000gn/T/CodeRunner/Untitled 6.php:35:
bool(false)
/private/var/folders/mf/cm46yj755lv9v_v4458953lc0000gn/T/CodeRunner/Untitled 6.php:36:
array(3) {
  [0] =>
  string(5) "00000"
  [1] =>
  NULL
  [2] =>
  NULL
}

PDOのエラーコード「00000」は成功を意味するので、本当に静かにループを終了して終わってしまう。

こういう静かなエラーに対応する方法はあるのだろうか?

8
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6