PDO::exec()允许(至少对某些驱动程序,如mysqlnd)一次执行多个语句。
这很好用,当我将几个查询传递给PDO::exec()
时,它们都会被执行:
$pdo->exec('DROP TABLE a; DROP TABLE b;');
我的PDO实例配置为抛出异常:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
如果第一个查询失败,则会按预期抛出异常:
$pdo->exec('DROP TABLE does_not_exist; DROP TABLE ok;'); // PDOException
但是当任何后续查询失败时,它会默默地忽略这个事实而你似乎没有办法知道它:
$pdo->exec('DROP TABLE ok; DROP TABLE does_not_exist;'); // no exception
var_export($pdo->errorInfo()); // array (0 => '00000', 1 => NULL, 2 => NULL)
有没有办法配置PDO,以便在{em>任何语句失败时exec()
抛出异常?
请注意,我目前没有更好的选择在自己的exec()
调用中运行每个查询,因为我正在编写一个读取SQL转储文件的工具。
答案 0 :(得分:1)
有趣的问题......我相信(如果我错了,请纠正我)这个"倍数" exec会在每个exec之后调用每个exec ...所以一旦你得到异常就会返回它,并且你的查询的执行就会停止。
用例: (dbname)测试包含2个表' a'和' b'
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "BEFORE:<br/>";
foreach($db->query("show tables;") as $row) echo $row[0] . "<br />";
$a = $db->exec("drop table b; drop table c");
echo "AFTER:<br/>";
foreach($db->query("show tables;") as $row) echo $row[0] . "<br />";
这里我得到结果:
BEFORE:
a
b
AFTER:
a
1 <--- ^.^
这在某种程度上是愚蠢的。但可能正确的解决方案是使用PDO交易。如果某些代码失败,您应该能够还原更改。基本上,如果你开始交易,你将在每次查询后关闭自动提交(最后提到的3个查询除外!!!)。恢复或提交将再次启用自动提交。
尝试代替$ db-&gt; exec(&#34; q1; q2; q3&#34;)......这样的事情:
try {
$db->beginTransaction();
$db->exec("drop table b;"); // -- note at the end of post!
$db->exec("drop table c;");
$db->commit();
} catch (PDOException $e) {
print_r($e);
$db->rollBack();
}
基本上这种方法很有效。无论其!
请注意,您不能使用TRUNCATE TABLE,因为此语句将触发提交,就像CREATE TABLE或DROP TABLE一样。
因此,如果您正在处理像DROP TABLE等的查询...在这种特殊情况下,您的正确解决方案是使用此查询而不是简单的drop:
SQL: DROP TABLE IF EXISTS `tablename`;
此声明不会触发异常;)
希望它有所帮助^。^
答案 1 :(得分: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;
}
如果第一条语句失败,query()
将引发异常。
如果第一条语句成功而第二条语句失败,则query()
将正常工作,而nextRowset()
将引发异常。
注意:一条失败的语句后不再执行其他语句。假设您有一个包含4条语句的SQL字符串,而第三条则失败:
query()
将成功nextRowset()
将成功并返回true
nextRowset()
会因异常而失败nextRowset()
将返回false
; 该语句未执行。如果您使用的是上面的代码,则无论如何它都会在遇到第一次异常时停止。