为何PDO中$sth2->errorInfo()返回$sth1的错误信息?(PostgreSQL)
这是PostgreSQL的PDO驱动一个容易踩坑的特性:当你的第一个语句$sth1执行出错后,PostgreSQL的数据库连接会进入一个错误状态,如果没有主动处理这个错误状态,后续执行的语句即使本身没有问题,调用它的errorInfo()时也可能返回之前连接上的错误信息。
具体来说,PDO的PDOStatement::errorInfo()在PostgreSQL驱动中,当当前语句本身没有错误时,会返回连接的最后错误记录——也就是$sth1执行时留下的错误。这和你理解的"每个语句句柄独立存储自身错误"的预期有偏差,是PostgreSQL驱动的特殊实现导致的。
这里有几个可行的方案:
启用PDO异常模式:在初始化PDO连接时,设置错误模式为异常,这样一旦语句执行出错就会立即抛出异常,强制你处理错误,避免错误状态残留到后续操作:
$db_conn = new PDO('pgsql:host=...;dbname=...', 'user', 'pass', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]);这样
$sth1->execute()时就会直接抛出异常,你可以用try/catch捕获处理,不会让错误状态影响到$sth2。主动检查每个语句的执行结果:在执行每个语句后,先判断是否执行成功,再继续后续操作。比如:
$sth1 = $db_conn->prepare("SELECT bla"); if (!$sth1->execute()) { // 处理$sth1的错误,比如打印错误信息 $error = $sth1->errorInfo(); echo "Error in sth1: " . $error[2]; // 可选择终止后续操作,避免错误状态扩散 } $sth2 = $db_conn->prepare("SELECT 1"); $sth2->execute(); // 此时$sth2->errorInfo()会返回自身的正确状态重置连接错误状态:如果必须保留错误状态到后续操作,可以在执行
$sth2前,执行一个简单的无错查询(比如SELECT 1)来重置连接的错误状态,不过这种方法不如前两种优雅。
你可以测试一下:在$sth1->execute()之后,先调用$sth1->errorInfo()获取并处理它的错误,再执行$sth2,此时$sth2->errorInfo()[2]就会返回null或者空字符串,符合预期。
内容的提问来源于stack exchange,提问作者Oto Shavadze

