php - PDO 持久连接的连接太多?

标签 php mysql pdo

我已经为此苦苦挣扎了很长一段时间,到了需要寻求帮助的地步,因为即使我进行了所有研究,我也无法理解为什么会发生这种情况。

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [1040] Too many connections'

这发生在加载单个页面 (index.php) 时,我是唯一的用户 (dev)。正如您在此处看到的,MySQL 连接限制设置为 @ 50,但我略微超过了它。这是对我重构代码之前创建的 100~ 个连接的改进。

MySQL connections before

这是页面加载一次后的统计信息。

MySQL connections after

我已将问题缩小为几个原因:

  • 我不完全理解 PDO/MySQL 连接是如何工作的。
  • 我在我的代码中创建了太多连接,尽管我试图只创建一个我可以共享的连接。
  • 我需要增加连接限制(似乎不太可能)。

我发现的大多数 SO 问题都告诉 OP 增加连接限制,但并不知道这是否是最佳解决方案,因此如果不需要,我会尽量避免这样做。一个页面加载 50 个连接似乎太多了。

这些是我在相关页面上实例化的类。

$DataAccess = new \App\Utility\DataAccess();
$DataCopyController = new App\Controllers\DataCopyController($DataAccess);
$DriveController = new App\Controllers\DriveController($DataAccess);
$Helper = new App\Utility\Helper();
$View = new App\Views\View();

我正在创建 DAL 对象,然后将其注入(inject)到需要它的类中。通过这种方式,我希望只创建一个对象和一个连接,但这显然不是正在发生的事情。在 DAL 类中,我还向每个查询方法添加了 $this->DbConnect->close()

这是 DataAccess() 类的构造函数。

public function __construct() {

    $this->DbConnect = new \App\Services\DbConnect();
    $this->db = $this->DbConnect->connect("read");
    $this->dbmod = $this->DbConnect->connect("write");

    $this->Helper = new Helper();
}

这是 DbConnect() 类。

类 DbConnect {

  private $db;
  private $dbmod;

  private function isConnected($connection) {
    return ($connection) ? TRUE : FALSE;
  } 

  public function connect($access) {

    $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false
                ];

    if ($access == "read") {
        if ($this->isConnected($this->db)) {
            return $this->db;
        } else {
            if (strpos($_SERVER['SERVER_NAME'], DBNAME_DEV) === false) {
                $this->db = new PDO("mysql:host=127.0.0.1; dbname=".DBNAME, 
                                                                    DBUSER, 
                                                                    DBPASS, 
                                                                    $options
                                                                       );
            } else {
                $this->db = new PDO("mysql:host=" . DBHOST_DEV ."; dbname=".DBNAME_DEV, 
                                                                   DBUSER, 
                                                                   DBPASS, 
                                                                   $options
                                                                       );
            }
            return $this->db;
        }
    } elseif ($access == "write") {
        if ($this->isConnected($this->dbmod)) {
            return $this->dbmod;
        } else {
            if (strpos($_SERVER['SERVER_NAME'], DBNAME_DEV) === false) {
                $this->dbmod = new PDO("mysql:host=127.0.0.1; dbname=".DBNAME, 
                                                                       DBUSER_MOD, 
                                                                       DBPASS, 
                                                                       $options
                                                                       );
            } else {
                $this->dbmod = new PDO("mysql:host=" . DBHOST_DEV . "; dbname=".DBNAME_DEV, 
                                                                       DBUSER_MOD, 
                                                                       DBPASS, 
                                                                       $options
                                                                       );
            }
        }
        return $this->dbmod;
    }
  }

  public function close() {
    $this->db = null;
    $this->dbmod = null;
  }
}

我还尝试在 index.php 上实例化 DbConnect() 类并注入(inject)它而不是 DataAccess() 但结果是一样的。

编辑: 我还想补充一点,这个MySQL服务器有两个数据库,prod和dev。我想连接限制在两者之间共享。但是,prod 数据库的流量非常小,我在那里没有看到这个错误。当我刷新统计信息时,没有与 prod 数据库的连接。

最佳答案

来自 PHP 手册 ~ http://php.net/manual/en/pdo.connections.php

Many web applications will benefit from making persistent connections to database servers. Persistent connections are not closed at the end of the script, but are cached and re-used when another script requests a connection using the same credentials.

所以我建议删除 DbConnection#close() 方法,因为您永远不想调用它。

同样来自手册...

Note:
If you wish to use persistent connections, you must set PDO::ATTR_PERSISTENT in the array of driver options passed to the PDO constructor. If setting this attribute with PDO::setAttribute() after instantiation of the object, the driver will not use persistent connections.

所以你会(至少)想要

new \PDO("mysql:host=127.0.0.1;dbname=" . DBNAME, DBUSER, DBPASS, [
    PDO::ATTR_PERSISTENT => true
]);

您还可以在构造函数中设置其他连接属性。

关于php - PDO 持久连接的连接太多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50244163/

相关文章:

php - 如何从 PHP 中的数组填充组合框?

php - 根据另一列值获取一列的值

mysql - 如何将 MySQL 表的唯一行转置为列作为查询

MySQL:除 root 用户外,用户 'test' @'localhost' 的访问被拒绝(使用密码:YES)

PHP Mysql 不删除行

php - 同一脚本中两个不同 MySQL 服务器的两个 PDO 数据库连接

php - 为多个 (128) 数据库值创建 (PHP) 重定向功能的有效方法

PHP 等效于 .NET/Java 的 toString()

mySQL 的 PHP 结果不显示输入值内的引号

php - 连接方法的方式和绑定(bind)变量的数量与中的标记数量不匹配。错误