【问题标题】:Closing an unbuffered MySQL query after PDO::exec()在 PDO::exec() 之后关闭无缓冲的 MySQL 查询
【发布时间】:2026-02-13 01:05:01
【问题描述】:

简而言之:有没有办法关闭/刷新/等使用 PDO::exec() 进行的无缓冲查询?

以代码为例:

abstract class baseTask {

    private $connection = false;

    protected function save($data) {
        if (!$this->connection) $this->connect();
        /*
        $this->tables() here returns the tables & fields a child class uses
        */
        foreach ($this->tables() as $table => $fields) {
            $sql = "SHOW TABLES LIKE '$table';";
            if($this->connection->exec($sql) === 0) {
                $sql = "CREATE TABLE IF NOT EXISTS $table (";
                $prefix = "";
                foreach ($fields as $name => $opts) {
                    $sql .= "$prefix$name $opts";
                    $prefix = ", ";
                }
                $sql .= ") ENGINE=InnoDB DEFAULT CHARSET=utf8;";
                if ($this->connection->exec($sql) == 0) {
                    var_dump($this->connection->errorInfo());
                }
            }
        }
    }

    private function connect() {
        $config = $this->config();
        $this->connection = new PDO("mysql:dbname=".$config['database'].";host=".$config['address'].";", $config['username'], $config['password'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''));
    }

    private function config() {
        return array(
          /* Config */
        );        
    }    
}

这里的目标是创建尚不存在的表,但显然“SHOW TABLES”查询在评估后仍处于活动状态,并且 PDO 根本无法运行第二个 exec()。

错误信息提示:

考虑使用 PDOStatement::fetchAll()

但显然在这种情况下这不是很方便。我将如何完成第一个查询,以便在执行第二个查询后不再有活动查询?

注意:我知道有一些方法可以解决这个问题,但我宁愿真正了解这里出了什么问题,如果不是这个,exec() 到底有什么用,如果我的问题有更优雅的解决方案。

【问题讨论】:

  • 你在找closeCursor()
  • @PatrickQ 不是,据我所知。 PDO 中没有 closeCursor() 方法,我也没有用于 closeCursor() 的 PDOStatement。
  • query()代替exec()怎么样?这将返回一个PDOStatement 对象。
  • 我很好奇,为什么您在执行CREATE TABLE IF NOT EXISTS 时对SHOW TABLES LIKE… 查询的结果感兴趣? IF NOT EXISTS 部分使您之前的检查毫无意义。

标签: php mysql pdo


【解决方案1】:

首先,if($this->connection->exec($sql) === 0) 不是一个好主意。

来自 PHP.net:

“PDO::exec() 不会从 SELECT 语句返回结果。对于只需要在程序期间发出一次的 SELECT 语句,请考虑发出 PDO::query()。”

Source

更改它并告诉我们它是否解决了问题。

【讨论】:

  • 我可以使用 exec 解决问题,但是在这种情况下,我并不是真的在寻找结果集,而是 exec 返回的内容:“PDO::exec() 在单个函数调用,返回受语句影响的行数。”那么我的用例不应该是 exec 专门用于的东西吗?
  • @Klasu 不是真的。 PDO::exec() returns the number of rows that were modified or deleted by the SQL statement you issued. If no rows were affected, PDO::exec() returns 0.您的第一个查询既没有修改也没有删除任何行。
  • true,通过exec发送的select查询总是返回0,测试没用。
  • 你所做的正是我的报价中描述的
  • 确实,我错误地认为 exec 可以使用 SHOW TABLES。我将其更改为: $stmt = $this->connection->query($sql); if(empty($stmt->fetchAll())) { ... 这样就解决了问题。谢谢你们!