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】:
好吧,“答案”贴在下面,但真正的答案是我应该停止对这个问题的思考,并在以后再回来,这对我来说似乎是最困难的事情之一去做。在我痴迷的某个时刻,我发现了一个神秘的<br/>
,然后是其中一个占位符值中的一些空格。我最终对变量执行substr($var, 0, -6)
以消除异常,直到注意到我无意中将<br/>
连接到填充变量的行的末尾; .<br/>
- 可能在删除一行输出代码进行测试时。
我曾与 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
谢谢大家的帮助。
【讨论】:
【参考方案2】:debugDumpParams
函数调用的输出看起来正确。
debugDumpParams
函数不显示绑定参数的值;它只显示 SQL 文本以及占位符名称/位置,以及它们各自的数据类型。
我不确定我是否理解你提出的问题。
不需要在 stmt 上调用fetchAll
方法,因为它是一个UPDATE
语句。
请注意,对于rowCount
,MySQL 返回语句实际更改的行数,而不是匹配的行数。也就是说,如果正在设置的列中的值已经设置为指定的值,那么 MySQL 不会将该行“计数”为受到影响。
【讨论】:
问题是为什么占位符似乎没有将值传递给mysql。即使发送一个简单的 SELECT$stmt = $db->prepare("SELECT * FROM nky_posts WHERE 'post_title'=:title")
也会返回 null。在 where 子句中正确返回实际数据。【参考方案3】:
我不知道您从哪里得到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->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
。甚至不确定它是否可以按照***.com/questions/16264769/… 工作
托管技术支持告诉我 .mysql_history 是空的。它可能只记录命令行查询。似乎很奇怪。他们“创建了一张票”。
@MikeiLL:你能用?
代替命名占位符试试这个吗?这可能有效。
@Mike ILL:默认情况下,PDO 不使用“服务器端”准备好的语句;我正在解决 Amal 所说的问题。在 SQL 文本中使用占位符与“服务器端”准备好的语句不是同义词;并非所有数据库和驱动程序都支持“服务器端”准备好的语句。 PDO 模仿它们。代码看起来像是在做准备好的语句,但 PDO 实际上是用文字创建一个 SQL 语句并将其发送到数据库。要查看 MySQL 服务器正在接收的语句,请启用 MySQL general_log。以上是关于MySQL 返回 PDO 占位符名称的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 语法错误 1064,带有 PDO UPDATE 语句(带有命名或未命名占位符)返回 WSOD
带有命名占位符的 PDO 准备好的语句 IN 子句无法按预期工作 [重复]