6

我偶然发现了(恕我直言,文档记录很差)事实,即默认情况下 PHP PDOMYSQL_ATTR_DIRECT_QUERY为其 MySQL 驱动程序启用了该标志。

这意味着它不是实际使用准备好的语句,而是模拟准备好的语句的行为。这意味着它将占位符客户端替换为转义值,并按原样将完整查询发送到数据库。

过去这样做是有充分理由的,因为在旧版本的 MySQL 中,prepared statements 会绕过查询缓存。但这已经有一段时间没有了。仍然有一点性能优势,因为它减少了从您的应用程序到数据库的往返次数,但我不确定这是否值得?

使用这种方法的明显缺点是我们仍然依赖于客户端转义,这通常是一个坏主意。过去我遇到过奇怪mysqli_real_escape_string的问题,由于某些字符集配置错误,无效字符被允许进入查询。我宁愿不再发生类似的事情。

我只是在这个问题上找到半真半假和肤浅的评论(例如,'是的,你可以启用它'或'它会导致“问题”')。寻找我不关闭它的真正原因?在 MySQL/PDO 中使用实际准备好的语句是否与模拟的准备好的语句不兼容?

我问的部分原因是因为我们使用依赖于 PDO 的 PHPActiverecord。它不附带测试,我不希望它在生产中突然中断,因为关闭模拟的准备好的语句会巧妙地改变某些边缘情况或其他情况下的行为。

(作为旁注,在任何人提出之前:检查PDO::ATTR_EMULATE_PREPARES将不起作用,因为它实际上并没有(完全)为 MySQL 驱动程序实现,您必须改为检查PDO::MYSQL_ATTR_DIRECT_QUERY。是的,那个花了我一段时间。)

澄清一下:我想知道是否有充分的理由关闭这种行为。不是我一开始就不应该关心的原因。

4

1 回答 1

4

该问题基于一个无效的假设:不完全支持 emulate prepares。(完全支持它们)。

事实上,MYSQL_ATTR_DIRECT_QUERY 只不过是 ATTR_EMULATE_PREPARES 的别名。

源代码中的证明:连接处理Attribute Getter CodeAttribute Setter Code

setter 代码是最能说明问题的。即:

390        case PDO_MYSQL_ATTR_DIRECT_QUERY:
391        case PDO_ATTR_EMULATE_PREPARES:
392            ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
393            PDO_DBG_RETURN(1);

有关为什么要绝对关闭模拟准备的更多信息,请参阅此答案

于 2013-09-15T16:53:38.357 回答