Слишком много соединений с постоянным соединением PDO? - PullRequest
0 голосов
/ 09 мая 2018

Я боролся с этим уже довольно давно, и до такой степени, что мне нужно обратиться за помощью, потому что даже после всех исследований, которые я провел, я не могу понять, почему это происходит.

Неустранимая ошибка: необработанное исключение «PDOException» с сообщением «SQLSTATE [HY000] [1040] Слишком много соединений»

Это происходит при загрузке одной страницы (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, затем внедряю его в классы, которые в нем нуждаются. Делая это таким образом, я надеялся создать только один объект и одно соединение, однако, очевидно, это не то, что происходит. Внутри класса 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;
  }
}

Я также пытался создать экземпляр DbConnect() класса на index.php и внедрить его вместо DataAccess(), но результат был тот же.

EDIT: Я также хочу добавить, что этот сервер MySQL имеет две базы данных, prod и dev. Я предполагаю, что лимит соединения распределяется между обоими. Однако база данных prod получает очень мало трафика, и я не вижу там этой ошибки. Когда я обновил статистику, к базе данных prod не было подключений.

1 Ответ

0 голосов
/ 09 мая 2018

Из руководства по PHP ~ http://php.net/manual/en/pdo.connections.php

Многие веб-приложения выиграют от постоянных подключений к серверам баз данных. Постоянные соединения не закрываются в конце скрипта, но кэшируются и используются повторно, когда другой скрипт запрашивает соединение, используя те же учетные данные.

Поэтому я бы посоветовал удалить метод DbConnection#close(), так как вы не захотите когда-либо вызывать его.

Также из руководства ...

Примечание:
Если вы хотите использовать постоянные соединения, вы должны установить PDO::ATTR_PERSISTENT в массиве параметров драйвера, передаваемых конструктору PDO. Если для этого атрибута задать значение PDO::setAttribute() после создания экземпляра объекта, драйвер не будет использовать постоянные соединения.

Итак, вы захотите (по крайней мере)

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

Вы также можете установить другие атрибуты соединения в конструкторе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...