[具有PDO::exec
时,PDO::query
和PDO::ATTR_PERSISTENT = true
之间似乎有所不同。使用PDO::exec
时,连接将不会被重用,最终由于MySQL似乎没有关闭(或重用)而导致“连接过多”错误。
例如,请参见以下小代码段:
<?php
$pdo_attr = [
PDO::ATTR_PERSISTENT => true,
];
$pdo = new PDO("mysql:host=mysql;dbname=empty", "root", "iamreallysecure", $pdo_attr);
// The following will give a to many connections error after a few browser refreshes (connection limit is set to 10)
var_dump($pdo->exec("SELECT 1"));
// While the following does NOT leave >10 connections open and continues to work
//var_dump($pdo->query("SELECT 1")->fetchAll());
[exec
将在系统上留下正在休眠的MySQL查询(由SHOW PROCESSLIST
观察),而query
不会触发此查询。
这是预期的吗? exec和query在这种情况下有什么区别?也许这是一个错误?
完整工作(泊坞窗)示例位于https://github.com/Mattie112/mysqltest
如果您将exec()
用于SELECT
,则说明您已经做错了。此函数(as is mentioned in the manual)不会从数据库中获取结果。它只能用于不产生结果集且没有变量输入的查询。如果查询产生结果,则需要使用相同的连接从MySQL获取此结果。
如果持久连接仍在使用中,则不能重用。发生这种情况的原因可能很多,其中之一是无法获取的结果。 MySQL将保持连接打开状态,等待客户端对结果集执行某些操作。从MySQL服务器整体获取结果后,它就可以接受新查询。
这不仅是持久连接的问题,因为如果您还通过普通连接一个接一个地使用exec()
,则未提取的结果集可能会成为问题。
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
];
$pdo = new PDO("mysql:host=localhost;dbname=test;port=3307", "root", "", $options);
// The following will give:
// SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
var_dump($pdo->exec("SELECT 1"));
var_dump($pdo->exec("SELECT 1"));
PDOException:SQLSTATE [HY000]:常规错误:2014当其他无缓冲查询处于活动状态时,无法执行查询。考虑使用PDOStatement :: fetchAll()。另外,如果您的代码只针对mysql运行,则可以通过设置PDO :: MYSQL_ATTR_USE_BUFFERED_QUERY属性来启用查询缓冲。在第16行的C:\ wamp64 \ www \ test \ index.php中]
从标题回答您的问题:是的。使用持久连接时,使用
exec()
和query()
之间存在差异,但是当不使用持久连接时,也存在差异。
tl; dr:请勿将exec()
用于产生结果的查询。请改用准备好的语句。
您设法在这里混淆了一切