【发布时间】:2018-10-19 00:40:39
【问题描述】:
我已经为此苦苦挣扎了很长一段时间,到了需要寻求帮助的地步,因为即使进行了所有研究,我也无法弄清楚为什么会发生这种情况。
致命错误:未捕获异常 'PDOException' 并带有消息 'SQLSTATE[HY000] [1040] Too many connections'
这发生在加载单个页面 (index.php) 时,我是唯一的用户 (dev)。正如您在此处看到的,MySQL 连接限制设置为 @ 50,但我差一点超过了这个限制。这是对我重构代码之前创建的 100~ 个连接的改进。
这是页面加载一次后的统计数据。
我已将问题缩小到几个原因:
- 我不完全了解 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 对象,然后将其注入到需要它的类中。通过这样做,我希望只创建一个对象和一个连接,但这显然不是正在发生的事情。在 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() 类并注入它而不是DataAccess(),但结果是一样的。
编辑: 我还想补充一点,这个 MySQL 服务器有两个数据库,prod 和 dev。我想连接限制在两者之间共享。但是,prod 数据库的流量很少,我在那里没有看到这个错误。当我刷新统计信息时,没有与 prod 数据库的连接。
【问题讨论】:
-
据我了解,您不会想要关闭持久连接。你在哪里打电话给
DbConnect#close()? -
另外,来自the manual ~ "如果你想使用持久连接,你必须在传递给PDO构造函数的驱动选项数组中设置PDO::ATTR_PERSISTENT。如果设置这个属性在对象实例化后使用 PDO::setAttribute(),驱动程序将不会使用持久连接。"
-
@Phil 谢谢。所以我的持久连接不是持久的。我也会尽量不关闭连接,让你知道结果。
-
@Phil 成功了!但似乎还是有什么奇怪的地方。在 mysql 服务器上,我看到 20 个持久连接。
db实例为 10,dbmod实例为 10。 -
我关闭了持久连接,但在页面加载时仍然只看到 2 个连接。似乎关闭连接可能是原因。奇怪,但这已经解决了。 @Phil,如果您添加答案,我会接受。