与PDO持久连接的连接太多了?

时间:2018-05-09 01:10:20

标签: php mysql pdo

我已经在这方面挣扎了很长一段时间,而且我需要寻求帮助,因为即使我完成了所有的研究,我也能做到这一点。 t了解为什么会发生这种情况。

  

致命错误:未捕获的异常' PDOException'消息' SQLSTATE [HY000] [1040]连接太多'

加载单个页面(index.php)时会发生这种情况,我是唯一的用户(dev)。正如你在这里看到的那样,MySQL连接限制设置为@ 50,但我差不多超过了它。这是对重构代码之前创建的100个连接的改进。

MySQL connections before

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

MySQL connections after

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

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

我发现的大多数SO问题都告诉OP增加连接限制,而不是真正知道这是否是最好的解决方案,所以我试图在这里避免这种情况,如果它&#39 ;不需要。一页加载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对象,然后将其注入需要它的类中。通过这样做,我希望只创建一个对象和一个连接,但这显然不是发生的事情。在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()类。

class 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;
  }
}

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

修改 我还想补充一点,这个MySQL服务器有两个数据库,prod和dev。我想两者之间共享连接限制。但是,prod数据库获得的流量非常少,我没有看到这个错误。当我刷新统计数据时,没有与prod数据库的连接。

1 个答案:

答案 0 :(得分:0)

From the PHP manual ~ 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.

So I would advise removing the DbConnection#close() method as you would not want to ever call this.

Also from the manual...

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.

So you'll want (at least)

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

You can also set your other connection attributes in the constructor.