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转储文件的工具.
正如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()将成功并返回truenextRowset()将失败并出现异常nextRowset()将返回false;该语句没有被执行。如果您使用上面的代码,它无论如何都会在第一个异常处停止。