【问题标题】:PDO insert query, why isn't this workingPDO 插入查询,为什么这不起作用
【发布时间】:2012-05-08 14:24:16
【问题描述】:

我愚蠢地用 mysqli 构建了我的 Web 应用程序。现在,我正在尝试将我的数据抽象层转换为 pdo,但由于某种原因,插入查询给我带来了麻烦。我的快捷插入函数是从控制器调用的,我希望将其保持为名称格式,并以表名和列/值数组作为参数。

我评论了我认为问题出在哪里。请帮忙。

function insert($table, array $columns_values) {        

    // connect to db
    $dbh = $this->db_connect();

    $i = 0;

    $columns = array();
    $values  = array();
    $params  = array();

    foreach($columns_values as $column => $value) {

        $i++;

        $param = array($i => $value);
        array_push($params, $param);

        array_push($columns, $column);
        array_push($values, '?');

    }

    // turn arrays into comma separated list
    $columns =      implode(",", $columns);
    $values  =      implode(",", $values);


    $stmt = $dbh->prepare("INSERT INTO $table ($columns) VALUES ($values)");


    foreach ($params as $param_stmt) {

             // i think this is where the problem is
            foreach ($param_stmt as $placeholder => $value) {

                $stmt->bindParam($placeholder, $value);

            }


    }

    $stmt->execute();

    return $stmt;

} // end insert()

【问题讨论】:

  • 快速提示 - 您可以尝试将其包装在 try/catch 块中,并在存在 PDO 错误时回显,或者回显 $stmt 以查看绑定是否存在错误。
  • $columns_values 原来的样子是什么?
  • “麻烦”和“问题”?这是你最好的描述吗?
  • 为什么要双循环绑定参数?在您的第一个循环中,您可以只执行$params[$i] = $value;,然后在绑定参数时执行一个循环。
  • 我不会说傻话。我在很多方面都更喜欢 mysqli。

标签: php pdo


【解决方案1】:

我不会按照你的方式去做。几分钟后,我想出了这个:

/**
 * Function to insert a list of values to the database.
 * 
 * @param PDO    $pdo
 * @param string $table
 * @param array  $columns_values
 *
 * @throws \Exception
 * @throws \PDOException
 */
function insert_to_db(PDO $pdo, $table, array $columns_values) {
    //Some data validation.
    if (empty($columns_values)) {
        throw new \Exception("Insert at least one value.");
    }
    if (empty($table)) {
        throw new \Exception("Table may not be empty.");
    }

    //Implode all of column names. Will become the columns part of the query.
    $str_columns = implode(", ", array_keys($columns_values));

    //Implode all column names after adding a : at the beginning.
    //They will become the placeholders on the values part.
    $prepared_column_names = array_map(function ($el) {
        return ":$el";
    }, array_keys($columns_values));
    $prepared_str_columns  = implode(", ", $prepared_column_names);

    //The query itself. Will look like "INSERT INTO `$table` (col1, col2, col3) VALUES (:col1, :col2, :col3);"
    $query = "INSERT INTO `$table` ($str_columns) VALUES ($prepared_str_columns);";

    //Prepare the query
    $stmt = $pdo->prepare($query);

    //Iterate over the columns and values, and bind the value to the placeholder
    foreach ($columns_values as $column => $value) {
        $stmt->bindValue(":$column", $value);
    }

    //Execute the query
    $stmt->execute();

}

我改变的地方

  1. 我没有在函数内部实例化 PDO 对象。函数需要一个才能工作,所以它应该是参数之一!
  2. 如果出现错误,我会抛出 Exception。这是处理错误的更好方法。
  3. 我使用命名占位符而不是未命名占位符(:name vs ?)。如果您需要调试,生成更具可读性、更易于跟踪的查询。
  4. 在代码中添加了 cmets。再说一次,你现在明白你写了什么,但从现在起 6 个月后你能理解吗?
  5. 我利用array_keys() 自动生成一个包含键(即列)的数组,而不是循环并手动添加一个。

一些提示

  • 当你实例化一个 PDO 对象时,确保它抛出 PDOExceptions 错误!像这样:

    new PDO($dsn, $user, $pass, array(PDO::PARAM_ERRMODE => PDO::ERRMODE_EXCEPTION));
    

    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::PARAM_ERRMODE, PDO::ERRMODE_EXCEPTION);
    

    这样,您不需要每次都明确检查错误,您可以使用单个 try catch 块来处理整个事情,这样就很好了:

    try {
        insert_to_db($pdo, $table, $array_of_columns_and_values);
    }
    catch (\Exception $e) { //Will catch all kinds of exceptions, including PDOExceptions
        echo $e->getMessage();
    }
    

【讨论】:

  • 你要记住,PDO 错误输出默认是静默的。奇怪我知道。当您实例化您的 PDO 类时,请确保存在以下内容...$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 否则错误代码将被抑制。
  • @MaurerPower:看看我的代码。我在实例化时将 ERRMODE 设置为 EXCEPTION(参见第一个代码块)。
  • @ytruth 我看到了,主要是在告诉悲伤的狗错误报告默认关闭。当我开始使用 PDO 时,我花了很长时间通过谷歌和这个网站来学习这个小知识。所以我主要是在解释你的第二个代码块语法以及哪一行实际初始化了错误检查。 PDO 一开始让我很困惑,我知道其他一些人也是如此。顺便说一句,很好的例子:) UPVOTED :)
【解决方案2】:

你还没有检查你的 prepare() 是否真的成功了:

$sql = "INSERT ....";
$stmt = $dbh->prepare($sql);
if (!$stmt) {
    die($sql . $dbh->errorInfo());
}

永远不要假设查询成功,尤其是当您完全动态地构建查询时。

【讨论】:

  • 最好使用PDOExceptions 而不是显式检查false
  • try{ ...stuff} catch (PDOException $e) { print $e->getMessage(); }
【解决方案3】:

没有看到你原来的 $columns_values 数组是什么样子的。

希望对你有帮助

<?php 
function insert($table, $values){
    $dbh = $this->db_connect();

    $fieldnames = array_keys($values[0]);

    $sql = "INSERT INTO $table";
    /*** set the field names ***/
    $fields = '( ' . implode(' ,', $fieldnames) . ' )';
    /*** set the placeholders ***/
    $bound = '(:' . implode(', :', $fieldnames) . ' )';
    /*** put the query together ***/
    $sql .= $fields.' VALUES '.$bound;

    //INSERT INTO testtable( id ,col1 ,col2 ) VALUES (:id, :col1, :col2 )

    /*** prepare and execute ***/
    $query = $dbh->prepare($sql);
    foreach($values as $vals){
        $query->execute($vals);
        /*  Array
        (
        [id]   =
        [col1] = someval1
        [col2] = Someval21
        )*/
    }

}
//Multi Insert
$insert = array(array('id'=>'','col1'=>'someval1','col2'=>'Someval21'),
                array('id'=>'','col1'=>'someval2','col2'=>'Someval22'),
                array('id'=>'','col1'=>'someval3','col2'=>'Someval23'),
                array('id'=>'','col1'=>'someval4','col2'=>'Someval24')
);

insert('testtable',$insert);
?>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-28
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多