【问题标题】:PDO fails a operation inside a transaction, but commit returns true. Why?PDO 使事务内部的操作失败,但提交返回 true。为什么?
【发布时间】:2014-05-07 12:01:59
【问题描述】:

我有以下代码

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

【问题讨论】:

    标签: php mysql pdo exception-handling


    【解决方案1】:

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

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

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

    如果您想为绑定参数强制匹配类型,则必须手动检查(例如,使用围绕 PDOStatement::bindParam 的包装器执行 gettype($param) 并将结果与​​指定类型进行比较)。

    【讨论】:

    • 哦,原来是 PHP 的问题,所以我更喜欢 Java 这样的强类型语言。而且参数绑定操作后有没有办法获取SQL?
    【解决方案2】:

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

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

    $usu_login 被强制转换为 int 并作为参数 3 绑定,这会创建如下查询:

    UPDATE ... WHERE idusuario = 0
    

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

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

    【讨论】:

      猜你喜欢
      • 2019-05-03
      • 2013-04-11
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 2022-12-03
      • 1970-01-01
      • 1970-01-01
      • 2014-07-20
      相关资源
      最近更新 更多