【问题标题】:What is the best way to insert multiple rows in PHP PDO MYSQL?在 PHP PDO MYSQL 中插入多行的最佳方法是什么?
【发布时间】:2014-12-14 21:05:25
【问题描述】:

假设我们要在一个表中插入多行:

$rows = [(1,2,3), (4,5,6), (7,8,9) ... ] //[ array of values ];

使用 PDO:

$sql = "insert into `table_name` (col1, col2, col3) values (?, ?, ?)" ;

现在,您应该如何插入行?像这样?

$stmt = $db->prepare($sql);

foreach($rows as $row){
  $stmt->execute($row);
}

或者,像这样?

$sql = "insert into `table_name` (col1, col2, col3) values ";
$sql .= //not sure the best way to concatenate all the values, use implode?
$db->prepare($sql)->execute();

哪种方式更快更安全?插入多行的最佳方法是什么?

【问题讨论】:

  • 批量插入总是更快。只需将值设置为 '(col1,col2,col3),(col1,col2,col3),...'
  • 安全风险如何?你能像下面这样内爆行吗:值 (implode(', ', $rows[0]), (implode(', ', $rows[1]), .... $db->prepare 方法仍然存在吗?如果需要,正确引用这些值?
  • 我不清楚您的安全问题是什么。如果您想以最方便的方式插入大量行,请分批进行。如果您担心数据是否被接受,那么要么先审查它,要么插入并处理任何异常。
  • 我的意思是 sql 注入。如果您是来自用户的原始行数组,您可以将其内爆并将其发送到 db->prepare 并执行它吗?我的意思是 prepare 方法会正确地转义字段吗?
  • 处理用户数据超出了您最初问题的范围。有许多可靠的“清理”输入和防止 sql 注入的方法。

标签: php mysql pdo sql-insert


【解决方案1】:

您至少有以下两种选择:

$rows = [(1,2,3), (4,5,6), (7,8,9) ... ];

$sql = "insert into `table_name` (col1, col2, col3) values (?,?,?)";

$stmt = $db->prepare($sql);

foreach($rows as $row)
{
    $stmt->execute($row);
}

OR:

$rows = [(1,2,3), (4,5,6), (7,8,9) ... ];

$sql = "insert into `table_name` (col1, col2, col3) values ";

$paramArray = array();

$sqlArray = array();

foreach($rows as $row)
{
    $sqlArray[] = '(' . implode(',', array_fill(0, count($row), '?')) . ')';

    foreach($row as $element)
    {
        $paramArray[] = $element;
    }
}

// $sqlArray will look like: ["(?,?,?)", "(?,?,?)", ... ]

// Your $paramArray will basically be a flattened version of $rows.

$sql .= implode(',', $sqlArray);

$stmt = $db->prepare($sql);

$stmt->execute($paramArray);

如您所见,第一个版本具有更简单的代码;但是第二个版本确实执行了批量插入。批量插入应该更快,但我同意 @BillKarwin 的观点,即在绝大多数实现中不会注意到性能差异。

【讨论】:

    【解决方案2】:

    我会采用第一种方法,使用一行参数占位符准备语句,然后使用执行一次插入一行。

    $stmt = $db->prepare($sql);
    
    foreach($rows as $row){
        $stmt-> execute($row);
    }
    

    它不如在一次插入中执行多行快,但它足够接近,您可能永远不会注意到差异。

    这样做的好处是使用代码非常容易。这就是为什么你仍然使用 PHP,为了开发人员的效率,而不是运行时的效率。

    如果您有很多行(数百或数千),并且性能是优先考虑的因素,您应该考虑使用LOAD DATA INFILE

    【讨论】:

      【解决方案3】:

      你也可以这样走:

      <?php
      $qmarks = '(?,?,?)'. str_repeat(',(?,?,?)', count($rows)-1);
      
      $sql = "INSERT INTO `table`(col1,col2,col3) VALUES $qmarks";
      $vals = array();
      foreach($rows as $row)
          $vals = array_merge($vals, $row);
      $db->prepare($sql)->execute($vals);
      

      老实说,我不知道哪个会更快,这完全取决于mysql和php服务器之间的延迟。

      【讨论】:

        【解决方案4】:
        /* test.php */
        
        <?php
        require_once('Database.php');
        
        $obj = new Database();
        $table = "test";
        
        $rows = array(
            array(
            'name' => 'balasubramani',
            'status' => 1
            ),
            array(
            'name' => 'balakumar',
            'status' => 1
            ),
            array(
            'name' => 'mani',
            'status' => 1
            )
        );
        
        var_dump($obj->insertMultiple($table,$rows));
        ?>
        
        /* Database.php */
        <?php
        class Database 
        {
        
            /* Initializing Database Information */
        
            var $host = 'localhost';
            var $user = 'root';
            var $pass = '';
            var $database = "database";
            var $dbh;
        
            /* Connecting Datbase */
        
            public function __construct(){
                try {
                    $this->dbh = new PDO('mysql:host='.$this->host.';dbname='.$this->database.'', $this->user, $this->pass);
                    //print "Connected Successfully";
                } 
                catch (PDOException $e) {
                    print "Error!: " . $e->getMessage() . "<br/>";
                    die();
                }
            }
        /* Insert Multiple Rows in a table */
        
            public function insertMultiple($table,$rows){
        
                $this->dbh->beginTransaction(); // also helps speed up your inserts.
                $insert_values = array();
                foreach($rows as $d){
                    $question_marks[] = '('  . $this->placeholders('?', sizeof($d)) . ')';
                    $insert_values = array_merge($insert_values, array_values($d));
                    $datafields = array_keys($d);
                }
        
                $sql = "INSERT INTO $table (" . implode(",", $datafields ) . ") VALUES " . implode(',', $question_marks);
        
                $stmt = $this->dbh->prepare ($sql);
                try {
                    $stmt->execute($insert_values);
                } catch (PDOException $e){
                    echo $e->getMessage();
                }
                return $this->dbh->commit();
            }
        
            /*  placeholders for prepared statements like (?,?,?)  */
        
            function placeholders($text, $count=0, $separator=","){
                $result = array();
                if($count > 0){
                    for($x=0; $x<$count; $x++){
                        $result[] = $text;
                    }
                }
        
                return implode($separator, $result);
            }
        
        }
        ?>
        

        上面的代码应该是使用 PDO 插入多条记录的好解决方案。

        【讨论】:

        • 请在您的帖子中添加一些解释。否则答案可能会被删除。
        • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。一个正确的解释would greatly improve 它的长期价值通过展示为什么这是一个很好的解决问题的方法,并将使它对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
        • 这基本上是这个答案的实现,stackoverflow.com/a/2098689/285587 几乎没有附加值
        猜你喜欢
        • 1970-01-01
        • 2022-12-07
        • 2010-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-13
        相关资源
        最近更新 更多