MySQL 返回 PDO 占位符名称

Posted

技术标签:

【中文标题】MySQL 返回 PDO 占位符名称【英文标题】:MySQL returning PDO placeholder names 【发布时间】:2014-04-11 13:09:58 【问题描述】:

有一个[similar post][1],但没有解决方案。

以下代码生成一个包含占位符名称的 mysql 查询:

    $the_image_itself = "abcde123def.jpg";
    $title = "A Book";
    $description = "Something to Read";
    $the_image_itself = "%".$the_image_itself;

    $stmt = $db->prepare("UPDATE nky_posts SET `post_title`=:title, `post_content`=:description WHERE `guid` LIKE :the_image_itself");

    $stmt->bindParam(':title', $title);
    $stmt->bindParam(':description', $description);
    $stmt->bindValue(':the_image_itself', $the_image_itself, PDO::PARAM_STR);
    $stmt->execute();
    $stmt->debugDumpParams();
    echo "<hr/>";
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    $affected_rows = $stmt->rowCount();

结果如下:

 start SQL: [105] UPDATE nky_posts SET `post_title`=:title,
     `post_content`=:description     
     WHERE `guid` LIKE :the_image_itself 
     Params: 3 Key: 
     Name:     [6] 
     :title paramno=-1 
     name=[6] ":title" 
     is_param=1 param_type=2 
     Key: Name: [12] :description 
     paramno=-1 name=[12] ":description" 
     is_param=1 param_type=2 
     Key: Name: [17] :the_image_itself paramno=-1 
     name=[17] ":the_image_itself" 
     is_param=1 param_type=2 

这是对象调用:

try
$db=new PDO('mysql:host=localhost;dbname=viewingr_ssdevwp;   charset=utf8',$db_username,$db_password);
 
catch(PDOException $e)
echo 'Error connecting to MySQL!: '.$e->getMessage();
exit();

【问题讨论】:

我在找什么?另外两个为什么不使用PDO::PARAM_STR 您遇到错误了吗?听起来您正在转储声明并查看您的参数占位符并假设这是问题所在。可能想读这个:***.com/questions/1786322/… 谢谢,@Fred -ii-。我不确定为什么 MySQL 用它们的名字而不是它们的值来解释占位符。我会尝试将 PDO::PARAM_STR 添加到前两个。 不客气。现在,我也不认为你应该使用LIKE :the_image_itself,它可能应该读作WHERE guid=:the_image_itself(或类似的东西)并在guid周围添加反引号(也许有一些关于PDO的东西我不知道, 然而)。我很难在 cmets 中展示它们。再说一次,我可能错了。我现在很难理解它。 我的上述评论可能部分错误,部分正确。我认为这是您的 WHERE 子句似乎不完整。 @MikeiLL 有点像WHERE guid='$something'... 【参考方案1】:

我不知道您从哪里得到debugDumpParams() 会显示原始 SQL 查询的印象——它不会。当使用参数化查询时,您在数据库中创建一个准备好的语句,然后然后发送参数值单独。它们没有一起发送,这意味着无法打印原始 SQL 查询。

debugDumpParams() 将只显示参数列表、它们的名称、类型等,但不显示它们的值。但是,您可以做的一件事是检查您的 MySQL 查询日志以查看已执行的原始 SQL 查询。

找到日志后,您可以使用以下命令查看最近执行的查询(前提是您具有 SSH 访问权限):

$ sudo tail -f /usr/local/mysql/data/yourQueryLog.log

上面的路径只是一个例子。您的系统上的实际路径可能不同。

【讨论】:

+1。你所说的 debugDumpParams 是真的。但是对于 MySQL,我相信 PDO 默认只模拟 MySQL 准备好的语句。要获得实际的“服务器端”准备好的语句,我认为您必须明确设置 PDO 选项...setAttribute(PDO::ATTR_EMULATE_PREPARES,false) 尝试添加$stmt-&gt;setAttribute(PDO::ATTR_EMULATE_PREPARES,false);。甚至不确定它是否可以按照***.com/questions/16264769/… 工作 托管技术支持告诉我 .mysql_history 是空的。它可能只记录命令行查询。似乎很奇怪。他们“创建了一张票”。 @MikeiLL:你能用?代替命名占位符试试这个吗?这可能有效。 @Mike ILL:默认情况下,PDO 不使用“服务器端”准备好的语句;我正在解决 Amal 所说的问题。在 SQL 文本中使用占位符与“服务器端”准备好的语句不是同义词;并非所有数据库和驱动程序都支持“服务器端”准备好的语句。 PDO 模仿它们。代码看起来像是在做准备好的语句,但 PDO 实际上是用文字创建一个 SQL 语句并将其发送到数据库。要查看 MySQL 服务器正在接收的语句,请启用 MySQL general_log。【参考方案2】:

好吧,“答案”贴在下面,但真正的答案是我应该停止对这个问题的思考,并在以后再回来,这对我来说似乎是最困难的事情之一去做。在我痴迷的某个时刻,我发现了一个神秘的&lt;br/&gt;,然后是其中一个占位符值中的一些空格。我最终对变量执行substr($var, 0, -6) 以消除异常,直到注意到我无意中将&lt;br/&gt; 连接到填充变量的行的末尾; .&lt;br/&gt; - 可能在删除一行输出代码进行测试时。

我曾与 hostMonster 技术支持人员联系以尝试获取 MySQL 日志,因为人们说这是唯一一个可以在您使用占位符时准确了解 MySQL 正在“看到”什么的地方,但他们不记录MySQL 查询,因为该文件将以 TB 为单位。

凌晨 3 点或 4 点,我放弃了。

今天带着新的头脑回到它,并通过以下步骤确认每个步骤都有效:

    创建一个没有 WHERE 或占位符的简单 SELECT 语句:

    $sql = "SELECT * FROM nky_posts";
    

    使用“=”(不是 LIKE)添加 WHERE 子句,其中变量是我知道在 DB 中的文字:

    $the_image = "image_url_from_phpMyAdmin";
    $sql = "SELECT post_title FROM nky_posts WHERE guid = $the_image";
    

    用一个持有已知值的占位符替换文字变量:

    $the_image = "image_url_from_phpMyAdmin";
    
    $stmt->bindParam(':the_image', $the_image, PDO::PARAM_STR);
    
    $sql = "SELECT post_title FROM nky_posts WHERE guid = :the_image";
    

    添加 LIKE 而不是 =(记得将占位符变量与“%”连接)

    $the_image = "%" . $the_image . "%";
    
    $stmt->bindParam(':the_image', $the_image, PDO::PARAM_STR);
    
    $sql = "SELECT post_title FROM nky_posts WHERE guid LIKE :the_image_itself";
    

    用动态变量替换“已知”变量(在这种情况下来自 XML 结果):

    basename($oBookNode->getElementsByTagName('actual-link')->item(0)->nodeValue);
    

    (使用 basename() 函数仅从 wordpress 数据库中的 URL 字符串返回图像名称)

    最后用我的 UPDATE 语句替换 SELECT 语句,添加两个额外的占位符来保存要插入的变量。最终代码:

    $sql = "UPDATE nky_posts SET post_title=:title, post_content=:description WHERE guid LIKE :the_image";
    
    $stmt = $db->prepare($sql);
    
    //foreach loop begins here
    foreach ($oDOM->getElementsByTagName('item') as $oBookNode)
    
    
    $the_image = basename($oBookNode->getElementsByTagName('actual-link')->item(0)->nodeValue);
    
    $title = $oBookNode->getElementsByTagName('title')->item(0)->nodeValue;
    
    $description = $oBookNode->getElementsByTagName('actual-content')->item(0)->nodeValue;
    
    //concat % to variable for LIKE clause (probably only needed first one in this case, but...)
    
    $the_image = "%" . $the_image . "%";
    
    
    $stmt->bindParam(':title', $title, PDO::PARAM_STR);
    
    $stmt->bindParam(':description', $description, PDO::PARAM_STR);
    
    $stmt->bindParam(':the_image_itself', $another_image_itself, PDO::PARAM_STR);
    
    $stmt->execute();
    //end foreach loop
    
    

    谢谢大家的帮助。

【讨论】:

【参考方案3】:

debugDumpParams 函数调用的输出看起来正确。

debugDumpParams 函数不显示绑定参数的值;它只显示 SQL 文本以及占位符名称/位置,以及它们各自的数据类型。

我不确定我是否理解你提出的问题。


不需要在 stmt 上调用 fetchAll 方法,因为它是一个 UPDATE 语句。

请注意,对于rowCount,MySQL 返回语句实际更改的行数,而不是匹配的行数。也就是说,如果正在设置的列中的值已经设置为指定的值,那么 MySQL 不会将该行“计数”为受到影响。

【讨论】:

问题是为什么占位符似乎没有将值传递给mysql。即使发送一个简单的 SELECT $stmt = $db-&gt;prepare("SELECT * FROM nky_posts WHERE 'post_title'=:title") 也会返回 null。在 where 子句中正确返回实际数据。

以上是关于MySQL 返回 PDO 占位符名称的主要内容,如果未能解决你的问题,请参考以下文章

为啥 PDO 不允许具有相同名称的多个占位符?

MySQL 语法错误 1064,带有 PDO UPDATE 语句(带有命名或未命名占位符)返回 WSOD

带有命名占位符的 PDO 准备好的语句 IN 子句无法按预期工作 [重复]

如何防止 PDO 将问号解释为占位符?

将 PDO 与 PostgreSQL 一起使用时如何忽略问号作为占位符

在 PDO 中的执行函数中将 NULL 值绑定到具有关联数组的命名占位符的问题