【问题标题】:How can I view the contents of a prepared statement?如何查看准备好的语句的内容?
【发布时间】:2011-01-19 05:24:25
【问题描述】:

我正在努力学习在 PHP 中使用准备好的语句和 mysqli,通常,如果我在查询时遇到问题,我只需将其回显到屏幕上,第一步看看它的样子。

如何使用准备好的语句做到这一点?

我想看看变量被替换后的 SQL 语句。

【问题讨论】:

    标签: php mysql mysqli


    【解决方案1】:

    使用准备好的语句:

    • 当您准备语句时,它会被发送到 MySQL 服务器
    • 绑定变量+执行语句时,只发送变量到MySQL服务器
    • 语句 + 绑定变量在 MySQL 服务器上执行 -- 无需在每次执行语句时都重新进行“准备”(这就是为什么准备好的语句在同一条语句时会提高性能的原因多次执行)

    在 PHP 端没有“构建” SQL 查询,因此无法实际获取该查询。

    这意味着如果您想查看 SQL 查询,则必须使用 SQL 查询,而不是准备好的语句。

    【讨论】:

    • 嗯,这有点烦人=\你会认为有办法获取执行的语句
    • 如果你在 PHP 端需要这个,主要是出于调试原因,我想,你可以“重新构造”相当于执行语句的 SQL 查询:你必须替换变量值的占位符 (转义数据,当然,将留给你) ;;;如果你经常需要这个,你应该能够为你编写一个函数;否则,var_dump 应该已经可以帮助您查看发送到 MySQL 服务器的数据。
    • @stomped 重点是没有执行语句。该步骤被完全跳过。
    • 这仅适用于实际准备好的语句。但也有emulated prepared statementswhich apparently are default in PDO
    • 您的论点是正确的,但是您可以将 sql 字符串与 ?参数的字符和一个字符串中的参数,并将其写入日志或显示以用于调试目的。在下面检查我的答案...
    【解决方案2】:
    对于使用 mysql_stmt_prepare() 和 mysql_stmt_execute() C API 函数执行的预处理语句,服务器将 Prepare 和 Execute 行写入一般查询日志,以便您知道语句何时准备和执行。
    [...] 服务器将以下行写入通用查询日志:
    准备 [1] SELECT ?
    执行 [1] 选择 3

    因此,出于调试目的,请激活 general log 并密切关注该文件。

    编辑:哦,这个问题有一个 [mysqli] 标签......完全忽略了这一点。
    如果该语句根本没有执行,您是否(双重/三重)检查了沿途没有发生错误?

    echo "<pre>Debug: start</pre>\n";
    
    $mysqli = new mysqli('localhost', 'localonly', 'localonly', 'test');
    if ($mysqli->connect_error) {
      die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
    }
    
    $result = $mysqli->query('CREATE TEMPORARY TABLE foo (id int auto_increment, x int, primary key(id))');
    if ( false=== $result) { 
     die('error : '. $mysqli->error);
    }
    
    $stmt = $mysqli->prepare('INSERT INTO foo (x) VALUES (?)');
    if ( false===$stmt ) {
      die ('prepare() failed: ' . $mysqli->error);
    }
    
    $result = $stmt->bind_param('i', $x);
    if ( false===$result ) {
      die('bind_param() failed');
    }
    
    $x = 1;
    $result = $stmt->execute();
    if ( false===$result ) {
      die('execute() failed: '.$stmt->error);
    }
    
    echo "<pre>Debug: end</pre>\n";
    

    【讨论】:

      【解决方案3】:

      当我需要调试带有参数的准备好的sql时,我通常会这样做。

      准备和执行示例:

      $sql = "SELECT VAL1, VAL2 FROM TABLE(?, '?', '?', '?', '?', ?, '?', '?', '?')";
      $prep = ibase_prepare( $sql ) or die("Error");
      $query = ibase_execute($prep, $param1, $param2, .....) or $err = true;
                                    ^^^^^^^^^^^^^^^^^^^^^^^
      

      调试结果 SQL 的简单方法是:

      printf( str_replace('?', '%s', $sql), $param1, $param2, ....);
                                            ^^^^^^^^^^^^^^^^^^^^^^
      

      你只需要做一次printf,将准备好的SQL字符串上的?替换为一个%sprintf 将全部解释为一个字符串,将每个参数视为将其放置在每个替换的 %s 上。

      【讨论】:

      • 您可以使用 PHP 的 'splat' 运算符 (...) 在函数中简化此操作
      • @kurdtpage。仅当参数在一个数组中时。
      【解决方案4】:

      我最近更新了这个项目,包括作曲家集成、单元测试和更好地处理通过引用接受参数(这需要更新到 php 5.6)。


      我创建了一组扩展默认 mysqlimysqli_stmt 类的类,以允许您查看潜在查询字符串的再现,这应该提供您正在寻找的内容:

      https://github.com/noahheck/E_mysqli

      这是您普通mysqli 对象的(接近)直接替换,当您prepare() 查询字符串时返回自定义mysqli_stmt 对象。绑定参数后,E_mysqli 将允许您将生成的查询字符串作为stmt 对象的新属性查看:

      $mysqli = new E_mysqli($dbHost, $dbUser, $dbPass, $dbName);
      
      $query = "INSERT INTO registration SET name = ?, email = ?";
      
      $stmt = $mysqli->prepare($query);
      
      $stmt->bind_param("ss", $_POST['name'], $_POST['email']);
      
      $stmt->execute();
      
      echo $stmt->fullQuery;
      

      会导致:

      INSERT INTO registration SET name = 'John Doe', email = 'john.doe@example.com'
      

      使用此扩展有一些注意事项(在 github 项目的 README 中进行了解释),但是对于解决应用程序的麻烦区域,或从程序转换到面向对象的样式,这应该为大多数人提供一定程度的帮助用户。

      正如我在 github 项目中所述,我没有任何使用 mysqli 扩展的实际经验,并且该项目是应其姊妹项目用户的要求创建的,因此可以提供任何反馈非常感谢在生产中使用它的开发人员。

      免责声明 - 正如我所说,我做了这个扩展。

      【讨论】:

        【解决方案5】:

        同意 Pascal MARTIN (+1),因此我建议使用另一种调试技术:var_dump() 或记录您插入语句中的每个变量,这样您应该能够确定它是错误数据还是逻辑错误错误的 SQL。

        【讨论】:

          【解决方案6】:

          您可以使用Lottip 之类的工具。这个想法就像 MySQL 代理一样。它解析 MySQL 数据包,提取查询及其参数,因此您可以查看准备好的语句及其内容。

          【讨论】:

          • 请在此处解释 Lottip 的概念和用法。链接不会永远存在。
          猜你喜欢
          • 2012-06-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-02
          相关资源
          最近更新 更多