在mysqli中插入许多值的最佳方法是什么?

时间:2013-03-01 01:56:08

标签: php mysql mysqli

我正在寻找一种SQL注入安全技术,用PHP和MySQLi一次插入大量行(约2000)。 我有一个包含所有必须包含的值的数组。 目前我正在这样做:

<?php
$array = array("array", "with", "about", "2000", "values");

foreach ($array as $one) 
{
    $query = "INSERT INTO table (link) VALUES ( ?)";
    $stmt = $mysqli->prepare($query);
    $stmt ->bind_param("s", $one);
    $stmt->execute();
    $stmt->close();
}
?>

我尝试了call_user_func_array(),但它导致了堆栈溢出。

更快的方法是什么(比如一次插入所有这些?),但仍然可以防止SQL注入(如准备好的语句)和stackoverflows?
谢谢!

4 个答案:

答案 0 :(得分:30)

通过将插入内容放入事务中,您应该能够大大提高速度。您还可以在循环之外移动prepare和bind语句。

$array = array("array", "with", "about", "2000", "values");
$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt ->bind_param("s", $one);

$mysqli->query("START TRANSACTION");
foreach ($array as $one) {
    $stmt->execute();
}
$stmt->close();
$mysqli->query("COMMIT");

编辑:

我在我的网络服务器上测试了10,000次迭代的代码。

没有交易:226 seconds. 使用交易:2 seconds.two order of magnitude speed increase,至少为该测试。

答案 1 :(得分:6)

再次尝试这一点,我不明白为什么原始代码不能进行微小修改:

$query = "INSERT INTO table (link) VALUES (?)";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("s", $one);

foreach ($array as $one) {
    $stmt->execute();
}
$stmt->close();

答案 2 :(得分:2)

是的,您可以手动构建一个大型查询,例如:

$query = "";
foreach ($array as $curvalue) {
  if ($query)
    $query .= ",";
  $query .= "('" . $mysqli->real_escape_string($curvalue) . "')";
}
if ($query) {
  $query = "INSERT INTO table (link) VALUES " . $query;
  $mysqli->query($query);
}

答案 3 :(得分:0)

您应该首先将数组转换为字符串。鉴于它是一个字符串数组(不是二维数组),您可以使用implode函数。

请注意,每个值都应括在括号中并正确转义以确保正确的INSERT语句并避免SQL注入的风险。为了正确转义,您可以使用PDOConnection的{​​{3}}方法 - 假设您通过PDO连接到MySQL。要对阵列的每个条目执行此操作,可以使用quote

在转义每个值并将它们插入单个字符串后,您需要将它们放入INSERT语句中。这可以使用array_map完成。

示例:

<?php
$connection = new PDO(/*...*/);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$dataToBeSaved = [
    'some',
    'data',
    'with "quotes"',
    'and statements\'); DROP DATABASE facebook_main; --'
];


$connection->query(
    sprintf(
        'INSERT INTO table (link) VALUES %s',
        implode(',',
            // for each entry of the array
            array_map(function($entry) use ($connection) { 
                // escape it and wrap it in parenthesis
                return sprintf('(%s)', $connection->quote($entry));
            }, $dataToBeSaved)
        )
    )
);

注意:根据您愿意插入数据库的记录数量,您可能希望将它们拆分为多个INSERT语句。