PHP PDO例外

时间:2017-01-18 20:29:58

标签: php mysql exception pdo transactions


我有一个问题,我很长时间都无法解决。我有一个像这样的简单DB类

class DB {

    private static $dbserver = "mysql:dbname=db;host=localhost";
    private static $dbuser = "root";
    private static $dbpass = "";

    public static function connectDB() {

        @$dbh = new PDO(self::$dbserver, self::$dbuser, self::$dbpass);
        $dbh->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
        $dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES utf8');

        return $dbh;
    }

一个Service Class,带有在DB中写入数据的方法。表的类型是InnoDB。服务类看起来像这样

function insert_data($data) {
    $error = NULL;
    try {
        $dbh = DB::connectDB();
        $dbh->beginTransaction();

        $query_insert_1 = 'INSERT INTO table (f1, f2, f3) VALUES (?,?,?)';
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $stmt = $dbh->prepare($query_insert_1);
        $stmt->execute(array($d1, $d2, $d3));

        $last_insert_id = $dbh->lastInsertId();

        $query_insert_2 = 'INSERT INTO table2 (f4, f5, f6) VALUES (?,?,?)';
        $stmt = $dbh->prepare($query_insert_2);
        $stmt->execute(array($last_insert_id, $d4, $d5));

        $dbh->commit();             
    }
    catch(Exception $e) {                       
        $dbh->rollback();
        $error = $e->getMessage();
    }
    $return = new Result($error ? 1 : 0, $error ? 0 : 1, $error ? $error : '', NULL);
    error_log(print_r($error,1));
    return $return;
}

如果我在函数insert_data中将PDO :: ATTR_ERRMODE设置为PDO :: ERRMODE_EXCEPTION,则PDO仅抛出异常。如果我在DB类中设置它,则不会抛出异常。这种行为的原因是什么?

当我在函数中设置常量时,我​​有解决方法抛出异常(PDO exception is not being thrown

感谢您的帮助

迈克尔

编辑: 我原来的代码是以下

class CarService {

private $dbh;

function __construct($dbh) {
    $this->dbh = $dbh;
}

function insert_car($customer_id, $brand, $model) {
    $error = NULL;

    try {
        $this->dbh->beginTransaction();

        $query_insert_car = 'INSERT INTO fahrzeug (kunde_id, fabrikat, modell) VALUES (?,?,?)';

        $stmt = $this->dbh->prepare($query_insert_car);
        $stmt->execute(array($customer_id, $brand, $model));
        // Get the ID of the last inserted car
        $last_insert_id = $this->dbh->lastInsertId();
        // Create the entry of the corresponding car version
        $query_insert_car_version = 'INSERT INTO fahrzeugversion (fahrzeug_id, version, fabrikat, modell) VALUES (?,?,?,?)';
        $stmt = $this->dbh->prepare($query_insert_car_version);
        $stmt->execute(array($last_insert_id, 1, $brand, $model));

        $this->dbh->commit();               
    }
    catch(Exception $e) {                       
        $this->dbh->rollback();
        $error = $e->getMessage();
    }

    $return = new Result(1, 0, NULL, NULL);
error_log(print_r($error,1));
    return $return;
}

new_car.php

<?php

require_once('DB.php');
require_once('CarService.php');
require_once('Result.php');

$dbh = DB::connectDB();
$car_service = new CarService($dbh);

$result = new Result(1, 0, NULL, NULL);

if (isset($_POST['fabrikat']) && isset($_POST['modell'])) {
    $brand = trim($_POST['fabrikat']);
    $model = trim($_POST['modell']);

    $result = $car_service->insert_car(1, $brand, $model);          
}   
print_r(json_encode($result));
?>

db.php中

<?php

class DB {

    private static $dbserver = "mysql:dbname=db;host=localhost";
    private static $dbuser = "root";
    private static $dbpass = "";

    public static function connectDB() {

        $dbh = new PDO(self::$dbserver, self::$dbuser, self::$dbpass);
        $dbh->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
        $dbh->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES utf8');
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $dbh;
    }

}
?>

2 个答案:

答案 0 :(得分:1)

PDO::ERRMODE_EXCEPTION属性添加到PDO连接过程

public static function connectDB() {

    $dbh = new PDO(self::$dbserver, self::$dbuser, self::$dbpass);
    $dbh->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
    $dbh->setAttribute(\PDO::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES utf8');
    $dbh->setAttribute(\PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $dbh;
}

并且在关闭它之前将为使用此连接的所有内容设置它。

现在您可以将其从您设置的任何其他地方删除

  

注:

     

也许这只是对何时抛出异常的误解。

     

当PDO :: ATTR_ERRMODE设置为PDO :: ERRMODE_EXCEPTION时,将抛出异常。

     

BUT:

     

如果PDO::ATTR_EMULATE_PREPARES = fale ->prepare()语句向数据库发出查询以进行编译,那么如果查询无法编译,您将获得->prepare()抛出的异常。

     

现在,如果PDO::ATTR_EMULATE_PREPARES = true准备语句很少。此时不会向数据库发出查询以进行编译。查询将作为->execute()处理的一部分发送到数据库进行编译,并且` - &gt; execute()语句将抛出与编译失败相关的任何异常抛出。

答案 1 :(得分:0)

看起来你的其他一些代码正在将PDO :: ERRMODE_EXCEPTION设置为另一个值。

如果您懒得编写一个隔离工作示例,其中包含您在此处发布的代码,您将看到该异常将被抛出。