• PHP PDO相关


    PDO 中对于错误的处理方式

    • PDO::ERRMODE_SILENT:默认方式,可通过检测函数返回值判断执行结果,当返回 false 时可通过 getCode、errorCode、errorInfo等方法获取具体错误信息
    • PDO::ERRMODE_WARNING:使用这个模式时,PDO将会发出一个传统的E_WARNING信息
    • PDO::ERRMODE_EXCEPTION:发生错误时 PDO 会抛出 PDOException,捕捉它并在 catch 块中进行 rollback 或其它业务的处理

    commit 的成功不等于业务的成功

    场景会员注册,需要插入两个表 tm、ta 的数据成功才成功。在 PDO 错误的操作中以为 commit 成功就是 commit 之前的数据操作都成功,或者说以为 commit 之前出现不成功的数据操作,commit 就会不成功,实际上并没有直接关系,因为 commit 结果仅对其自身负责,并不表示完整业务的结果。

    // 错误的示范
    // 假设 tm 表的 id 字段不允许重复且已经存在 id=0005 的记录,因此 $sql0 执行会出错,ta 表不存在重复索引
    $sql0 = 'insert into tm(`id`) values (:id);';
    $sql1 = 'insert into ta(`id`) values (:id);';
    
    $pdo = new PDO(dsn, user, pwd);
    $pdo->beginTransaction();
    // prepare 不会出错,因为sql语法正确
    $stmt = $pdo->prepare($sql0);
    // execute 会出错, execute 返回 false
    $stmt->execute(array(':id'=>'0005'));
    
    $stmt=$pdo->prepare($sql1);
    // ta 表执行成功,返回 true
    $stmt->execute(array(':id'=>'0005'));
    
    // 这里 commit 返回 true
    $ok = $pdo->commit();
    if($ok){
    // 根据 $ok 判断,导致了误以为整个数据操作正确,实际 $sql0 业务执行错误,仅 $sql1 执行成功
    }
    

    解决方案一:显式设置 PDO 错误处理模式,使其暴露 PDOException,在业务中捕捉并处理,达到要么成功要么回滚的要求。

    // 解决方案一的示范
    // 假设 tm 表的 id 字段不允许重复且已经存在 id=0005 的记录,因此 $sql0 执行会出错,ta 表不存在重复索引
    $sql0 = 'insert into tm(`id`) values (:id);';
    $sql1 = 'insert into ta(`id`) values (:id);';
    
    // 在构造实例时设置 PDO 发生错误的处理方式是 PDOException
    // 也可以在构造之后,使用 $pdo->setAttribute 方法设置
    $pdo = new PDO(dsn, user, pwd, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
    try {
        $pdo->beginTransaction();
        // prepare 不会出错,因为sql语法正确
        $stmt = $pdo->prepare($sql0);
        // execute 会出错, execute 返回 false
        // 因此到这里就会抛出 PDOException 被 catch
        // 不会往下执行
        $stmt->execute(array(':id' => '0005'));
    
        $stmt = $pdo->prepare($sql1);
        // ta 表执行成功,返回 true
        $stmt->execute(array(':id' => '0005'));
    
        // 这里 commit 返回 true
        $ok = $pdo->commit();
    } catch (PDOException $e) {
        $pdo->rollBack();
    }
    

    解决方案二:不改变默认模式,手动判断各个方法的返回值,当执行不成功也就是 false 时进行回滚处理,控制完整的业务流程。

    // 解决方案二的示范
    // 假设 tm 表的 id 字段不允许重复且已经存在 id=0005 的记录,因此 $sql0 执行会出错,ta 表不存在重复索引
    $sql0 = 'insert into tm(`id`) values (:id);';
    $sql1 = 'insert into ta(`id`) values (:id);';
    
    $pdo = new PDO(dsn, user, pwd);
    
    $pdo->beginTransaction();
    // prepare 不会出错,因为sql语法正确
    $stmt = $pdo->prepare($sql0);
    // execute 会出错, execute 返回 false
    // 立即处理或标记返回值之后处理
    $ok0 = $stmt->execute(array(':id' => '0005'));
    
    $stmt = $pdo->prepare($sql1);
    // ta 表执行成功,返回 true
    $ok1 = $stmt->execute(array(':id' => '0005'));
    
    if ($ok0 && $ok1) {
        $ok = $pdo->commit();
    } else {
        $pdo->rollBack();
    }
    
    ## 不重要的其实最重要
  • 相关阅读:
    windows 安装 nodejs指定版本
    Xshell通过ssh登录远程服务器(秘钥)
    CentOS7 防火墙操作
    Linux系统MySQL开启远程连接
    PHP 下载图片文件并压缩文件成zip
    thinkphp 中更新数据字段,同时某字段值++操作(报错TP5.1不支持的数据表达式:[exp]的解决办法)
    layui的loading加载中
    Linux下面安装swoole
    windows 下cmd命令删除文件或者文件夹
    PHP 删除某目录下的全部文件
  • 原文地址:https://www.cnblogs.com/cinlap/p/14344539.html
Copyright © 2020-2023  润新知