【问题标题】:Why can't I run two mysqli queries? The second one fails [duplicate]为什么我不能运行两个 mysqli 查询?第二个失败[重复]
【发布时间】:2012-06-07 00:23:01
【问题描述】:

是否可以有两个这样的mysqli查询?

mysqli_query($dblink, "INSERT INTO images (project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name) VALUES ('$project_id', '$user_id', '$image_name', '$date_created', '$link_to_file', '$thumbnail', '$ImageName')");
mysqli_query($dblink, "INSERT INTO images_history (project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name, day, month, year) VALUES ('$project_id', '$user_id', '$image_name', '$date_created', '$link_to_file', '$thumbnail', '$ImageName', '$day', '$month', '$year')");

基本上我想更新我的数据库中的两个表。有没有更好的方法来做到这一点?

【问题讨论】:

  • 可以运行 2 个查询,当然可以。
  • 您说有可能,但上述方法不起作用。它只是插入到图像中,而不是插入到 images_history 中。
  • 好吧,也许您应该检查特定查询是否有问题,它与任何其他查询无关。
  • @PartisanEntity 您应该将mysql_error() 更改为mysqli_error(),因为两者是不同的,当mysqli 查询失败时,mysql_error() 不会给您任何回复。
  • 当然您可以运行两个或十个或任意数量的查询。数量无所谓。问题与数量无关。只是执行第二个查询时出错。

标签: php mysqli


【解决方案1】:

mysqli_multi_query() 是可能的。

例子:

<?php

$mysqli = new mysqli($host, $user, $password, $database);

// create string of queries separated by ;
$query  = "INSERT INTO images (project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name) VALUES ('$project_id', '$user_id', '$image_name', '$date_created', '$link_to_file', '$thumbnail', '$ImageName');";
$query .= "INSERT INTO images_history (project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name, day, month, year) VALUES ('$project_id', '$user_id', '$image_name', '$date_created', '$link_to_file', '$thumbnail', '$ImageName', '$day', '$month', '$year');";

// execute query - $result is false if the first query failed
$result = mysqli_multi_query($mysqli, $query);

if ($result) {
    do {
        // grab the result of the next query
        if (($result = mysqli_store_result($mysqli)) === false && mysqli_error($mysqli) != '') {
            echo "Query failed: " . mysqli_error($mysqli);
        }
    } while (mysqli_more_results($mysqli) && mysqli_next_result($mysqli)); // while there are more results
} else {
    echo "First query failed..." . mysqli_error($mysqli);
}

关键是您必须使用mysqli_multi_query,如果您想在一次调用中执行多个查询。出于安全原因,mysqli_query 不会执行多个查询以防止 SQL 注入。

还要记住mysqli_store_result 的行为。如果查询没有结果集(INSERT 查询没有),则返回 FALSE,因此您还必须检查 mysqli_error 以查看它返回的空字符串表示 INSERT 成功。

见:
mysqli_multi_query
mysqli_more_results
mysqli_next_result
mysqli_store_result

【讨论】:

  • 我知道这是旧的,但对于仍在使用 mysqli_multi_query 的人,正如@dre010 解释的那样:出于安全原因,mysqli_query 不会执行多个查询以防止 SQL 注入。所以我认为你应该考虑将你的查询分成几个单独的查询并使用准备好的语句
  • 我对此感到困惑。我正在尝试对此进行调整,以便我可以说,'如果通过搜索第一个表找到了一个字符串,则返回结果。如果第一个表没有找到,第二个表也没有找到,则插入到第二个表中。所以运行第一个 SELECT 语句,但如果第一个没有返回结果,则只运行第二个。有没有办法区分您希望在 mysqli_multi_query 中使用哪个 SELECT 语句?
  • @DjDaihatsu 我会说不要使代码过于复杂,只需将两个选择编写为单独的查询而不使用 multi_select。根据您的表结构或选择列表,区分的方法是查看结果中返回了哪些行,您将知道它来自哪个语句,但这会增加额外的不必要的逻辑,如果您只做两个可以避免单独调用 mysqli_query。
  • 谢谢@drew010!那么在关闭连接之前在数据库中的不同表上运行多个单独的选择语句是可以接受的吗?我的代码中一定有另一个错误,因为我无法从第二个表(在同一个数据库中)返回结果。
  • @DjDaihatsu 完全可以接受。使用单独的结果集,您甚至可以向其他表发出单独的查询,同时仍然使用其他结果。但是在同一个连接上对不同的表发出多个选择是完全可以的。
【解决方案2】:

这是可能的。只需使用两个准备好的查询。

$stmt = $dblink->prepare("INSERT INTO images 
(project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name) 
VALUES (?,?,?,?,?,?,?)");
$stmt->bind_param("ssssss", $project_id, $user_id, $image_name, $date_created, $link_to_file, $thumbnail, $ImageName);
$stmt->execute();

$stmt = $dblink->prepare("INSERT INTO images_history 
(project_id, user_id, image_name, date_created, link_to_file, link_to_thumbnail, given_name, day, month, year)
VALUES (?,?,?,?,?,?,?,?,?,?)");
$stmt->bind_param("ssssssssss", $project_id, $user_id, $image_name, $date_created, $link_to_file, $thumbnail, $ImageName, $day, $month, $year);
$stmt->execute();

它不仅更干净,而且100% 安全地防止 SQL 注入

如果您的某个查询失败,只需ask mysqli for the error message and then fix the error


Stack Overflow 上的Some answers 如此自相矛盾,以至于令人兴奋

关键是如果你想在一次调用中执行多个查询,你必须使用 mysqli_multi_query。 出于安全原因,mysqli_query 不会执行多个查询以防止 SQL 注入

它基本上说,“关键是你必须使用没有安全锁扣的枪械,因为普通武器不会让你射中自己的脚。所以这里是分解它的方法,现在你可以一枪就废了自己!”

尽管 OP 没有询问如何在一次调用中运行两个查询,尽管引用了明确警告,在一次调用中运行多个查询的能力是固有的危险,答案漫不经心地提供了规避此限制的方法。

最糟糕的是,所有这些危险而繁琐的混乱都是徒劳的。仅仅是因为在一次调用中运行多个查询并不是一个单一的原因。一个一个地运行查询是数据库 API 的用途

【讨论】:

    【解决方案3】:

    一劳永逸!使用此函数可以在脚本中的任意位置获取无限数量的查询结果。

    功能:

    您只需将多查询的输出传递给函数,它就会返回在每个查询中找到的所有结果和错误。

      function loop_multi($result){
        //use the global variable $conn in this function
        global $conn;
        //an array to store results and return at the end
        $returned = array("result"=>array(),"error"=>array());
        //if first query doesn't return errors
          if ($result){
            //store results of first query in the $returned array
            $returned["result"][0] = mysqli_store_result($conn);
            //set a variable to loop and assign following results to the $returned array properly
            $count = 0;
            // start doing and keep trying until the while condition below is not met
            do {
                //increase the loop count by one
                $count++;
                //go to the next result
                mysqli_next_result($conn);
                //get mysqli stored result for this query
                $result = mysqli_store_result($conn);
                //if this query in the loop doesn't return errors
                if($result){
                  //store results of this query in the $returned array
                  $returned["result"][$count] = $result;
                //if this query in the loop returns errors
                }else{
                  //store errors of this query in the $returned array
                  $returned["error"][$count] = mysqli_error($conn);
                }
            }
            // stop if this is false
            while (mysqli_more_results($conn));
          }else{
            //if first query returns errors
            $returned["error"][0] = mysqli_error($conn);
          }
        //return the $returned array
        return $returned;
      }
    

    用法:

    $query  = "INSERT INTO table1 (attribute1) VALUES ('value1');";
    $query .= "INSERT INTO table2 (attribute2) VALUES ('value2');";
    $query .= "SELECT * FROM table3;";
    
    //execute query
    $result = mysqli_multi_query($conn, $query);
    //pass $result to the loop_multi function
    $output = loop_multi($result);
    

    输出

    $output 包括按查询排序的 2 个数组“结果”和“错误”。例如,如果您需要检查执行第三个查询时是否发生任何错误并获取其结果,您可以这样做:

    if(isset($output['error'][2]) && $output['error'][2] !== ""){
      echo $output['error'][2];
    }else{
      while($row = $output['result'][2]->fetch_assoc()) {
        print_r($row);
      }
    }
    

    【讨论】:

    • 请参阅Your Common Sense's later answer 重新安全和 SQL 注入。底线:使用mysqli_multi_query 会使自己面临 SQL 注入攻击。为了安全起见,请勿致电mysqli_multi_query。相反,要求调用者将每个单独的查询作为其自己的字符串传递。所以输入参数应该是一个查询字符串数组。然后,给每个人打电话mysqli_query。您仍然可以像以前那样打包结果,但这将避免 一些但不是全部 SQL 注入攻击。 [为避免所有攻击参数化所有查询。]
    猜你喜欢
    • 1970-01-01
    • 2021-01-02
    • 2017-06-25
    • 2018-08-17
    • 1970-01-01
    • 2020-03-08
    • 1970-01-01
    • 2015-10-24
    相关资源
    最近更新 更多