簡體   English   中英

與PDO持久連接的連接過多?

[英]Too many connections with PDO persistent connection?

我已經為此苦苦掙扎了很長時間了,這是我需要尋求幫助的地步,因為即使進行了所有研究,我仍然無法理解為什么會發生這種情況。

致命錯誤:消息為“ SQLSTATE [HY000] [1040]的連接過多,未捕獲的異常” PDOException”

這是在加載單個頁面( index.php )時發生的,並且我是唯一的用戶(dev)。 正如您在此處看到的那樣,MySQL連接限制設置為50,但我幾乎超過了該限制。 這是對重構代碼之前創建的100個連接的改進。

MySQL之前的連接

頁面加載一次后的統計信息如下。

之后的MySQL連接

我已將問題縮小為幾個原因:

  • 我不完全了解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數據庫的連接。

從PHP手冊〜http://php.net/manual/zh/pdo.connections.php

與Web服務器建立持久連接將使許多Web應用程序受益。 持久連接不會在腳本結尾處關閉,而是在另一個腳本使用相同憑據請求連接時被緩存並重新使用。

因此,我建議刪除DbConnection#close()方法,因為您永遠都不想調用它。

也是從手冊...

注意:
如果希望使用持久連接,則必須在傳遞給PDO構造函數的驅動程序選項數組中設置PDO::ATTR_PERSISTENT 如果在實例化對象后使用PDO::setAttribute()設置此屬性,則驅動程序將不使用持久連接。

所以你會想要(至少)

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

您還可以在構造函數中設置其他連接屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM