PDO在事务内部失败,但commit返回true。为什么?

时间:2014-05-07 12:02:00

标签: php mysql pdo exception-handling

我有以下代码

public function actualizarLogin($idusuario, $usu_login=NULL, 
            $usu_passwd=NULL) {
        $result=false;
        try {
            $db=new PDO(MYSQL_CON, MYSQL_USER, MYSQL_PASSWD,
                    array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
            try {
                $db->beginTransaction();
                $sql="UPDATE usuario SET usu_login=?, usu_passwd=? 
                        WHERE idusuario=?";
                $pstmt=$db->prepare($sql);
                $pstmt->bindParam(1, $usu_login, PDO::PARAM_STR);
                if($usu_passwd==null) {
                    $pstmt->bindParam(2, $usu_passwd, PDO::PARAM_NULL);
                } else {
                    $pstmt->bindParam(2, crypt($usu_passwd, CRYPT_MD5), PDO::PARAM_STR);
                }
                //Accidentaly using wrong variable here
                $pstmt->bindParam(3, $usu_login, PDO::PARAM_INT);
                $pstmt->execute();
                //But commit return true and no Exception is thrown
                $result=$db->commit();              
            } catch (PDOException $e) {
                $result=$e->getMessage();
                $db->rollBack();
                throw new RPC_INTERNAL_ERROR();
            }
        }catch (PDOException $e) {  
            $result=$e->getMessage();
            throw new RPC_INTERNAL_ERROR();
        }
        return $result;

RPC_INTERNAL_ERROR是zoservices的一个例外,zoservices是我用于JSON-RPC服务器的库,并且这个方法是从客户端调用的。 正如您可以阅读代码中的注释,我犯了一个错误,一个非常人性化的东西,我正在使用错误的变量来绑定最后一个参数,我告诉它将它绑定为一个整数,而实际上是字符串(它是登录而不是id)。但由于某种原因,即使我告诉在失败时抛出异常也没有这样的异常,但最糟糕的是提交返回true ...为什么?我花了一些宝贵的时间才发现这个错误,因为PDO并没有告诉我任何相关信息。有办法处理这些错误吗?

2 个答案:

答案 0 :(得分:0)

当您这样做时,PDO不会抛出,因为这些输入参数对您来说是指定类型的coerced。就数据库而言,不会发生错误,因为它接收列数据类型的有效值。

这种行为在整个PHP中很普遍,因为替代方案是这段代码不起作用:

$foo = "4"; // not techically an int
$pstmt->bindParam(3, $foo, PDO::PARAM_INT);
$pstmt->execute();

如果要强制绑定参数的匹配类型,则必须手动检查(例如,使用PDOStatement::bindParam的{​​{1}}包装,并将结果与​​指定的类型进行比较。

答案 1 :(得分:0)

没有错误,因为没有错误。

$pstmt->bindParam(3, $usu_login, PDO::PARAM_INT);

$usu_login被强制转换为int并绑定为参数3,它创建了一个查询行:

UPDATE ... WHERE idusuario = 0

执行时,没有任何反应,因为WHERE条件不适用于任何事情(大概)。 PDO::PARAM_INT不会导致错误,因为它只是确保参数绑定为int,并且查询本身完全正常,即使它什么都不做(这是一个完全有效的结果)。

您可能需要检查$pstmt->rowCount()以查看受影响的行数是否符合您的预期。