当PDO :: exec()中的任何语句失败时,有没有办法抛出异常?

Ben*_*min 8 php pdo

PDO :: exec()允许(至少对某些驱动程序,如mysqlnd)一次执行多个语句.

这很好用,当我向PDO::exec()他们传递几个查询时,它们都会被执行:

$pdo->exec('DROP TABLE a; DROP TABLE b;');
Run Code Online (Sandbox Code Playgroud)

我的PDO实例配置为抛出异常:

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Run Code Online (Sandbox Code Playgroud)

如果第一个查询失败,则会按预期引发异常:

$pdo->exec('DROP TABLE does_not_exist; DROP TABLE ok;'); // PDOException
Run Code Online (Sandbox Code Playgroud)

但是当任何后续查询失败时,它会默默地忽略这个事实而你似乎没有办法知道它:

$pdo->exec('DROP TABLE ok; DROP TABLE does_not_exist;'); // no exception
var_export($pdo->errorInfo()); // array (0 => '00000', 1 => NULL, 2 => NULL)
Run Code Online (Sandbox Code Playgroud)

有没有办法配置PDO,以便exec()任何语句失败时抛出异常?

请注意,我目前没有明显更好的选择在自己的exec()调用中运行每个查询,因为我正在编写一个读取SQL转储文件的工具.

Ben*_*min 0

正如bug #61613中提到的,如果任何语句失败,则可能会出现异常。

解决方案是使用模拟的准备(默认情况下打开)和PDOStatement::nextRowset()

$pdo = new PDO(...);

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// on by default, not necessary unless you need to override a previous configuration
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

try {
    $statement = $pdo->query('DELETE FROM unknown_a; DELETE FROM unknown_b;');

    // loop through all the statements
    while ($statement->nextRowset());
} catch (PDOException $e) {
    echo $e->getMessage(), PHP_EOL;
}
Run Code Online (Sandbox Code Playgroud)

如果第一条语句失败,query()将抛出异常。

如果第一个语句成功而第二个语句失败,query()则将正常工作,并nextRowset()会引发异常。

警告:在失败的语句之后不会执行任何进一步的语句。假设您有一个包含 4 条语句的 SQL 字符串,而第三条语句失败:

  • 第一个声明:query()将会成功
  • 第二条语句:nextRowset()将成功并返回true
  • 第三条语句:nextRowset()将失败并出现异常
  • 第四条语句:nextRowset()将返回false该语句没有被执行

如果您使用上面的代码,它无论如何都会在第一个异常处停止。