Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Cách khắc phục Thông báo:SQLSTATE [08004] [1040] Quá nhiều kết nối

Model của bạn lớp khởi tạo một Database mới đối tượng trong phương thức khởi tạo của nó, mỗi khi bạn khởi tạo một Model (hoặc bất kỳ lớp nào mở rộng nó), bạn đang có hiệu lực mở một mới kết nối cơ sở dữ liệu. Nếu bạn tạo một số Model các đối tượng, sau đó mỗi đối tượng có kết nối cơ sở dữ liệu độc lập của riêng nó, điều này không phổ biến, thường là không cần thiết, không sử dụng tốt tài nguyên mà còn có hại vì nó đã sử dụng hết tất cả các kết nối có sẵn của máy chủ.

Ví dụ:lặp để tạo một mảng Model đối tượng:

// If a loop creates an array of Model objects
while ($row = $something->fetch()) {
  $models[] = new Model();
}
// each object in $models has an independent database connection
// the number of connections now in use by MySQL is now == count($models)

Sử dụng chèn phụ thuộc:

Giải pháp là sử dụng tính năng tiêm phụ thuộc và vượt qua cơ sở dữ liệu Database đối tượng vào Model::__construct() thay vì cho phép nó tự khởi tạo.

class Model {

  protected $_db;

  // Accept Database as a parameter
  public function __construct(Database $db) {
    // Assign the property, do not instantiate a new Database object
    $this->_db = $db;
  }
}

Khi đó, để sử dụng nó, mã điều khiển (mã sẽ khởi tạo các mô hình của bạn) tự nó sẽ gọi new Database() chỉ một lần. Đối tượng đó được tạo bởi mã điều khiển sau đó phải được chuyển đến các hàm tạo của tất cả các mô hình.

// Instantiate one Database
$db = new Database();

// Pass it to models
$model = new Model($db);

Đối với trường hợp sử dụng mà bạn thực sự cần một kết nối cơ sở dữ liệu độc lập khác cho một mô hình, bạn có thể cung cấp cho nó một kết nối khác. Đặc biệt, điều này rất hữu ích để kiểm tra . Bạn có thể thay thế một đối tượng cơ sở dữ liệu thử nghiệm hoặc một đối tượng giả.

// Instantiate one Database
$db = new Database();
$another_db = new Database();

// Pass it to models
$model = new Model($db);
$another_model = new Model($another_db);

Kết nối liên tục:

Như đã đề cập trong các nhận xét, sử dụng kết nối liên tục có thể là một giải pháp, nhưng không phải là giải pháp mà tôi muốn đề xuất . PDO sẽ cố gắng sử dụng lại kết nối hiện có với cùng thông tin xác thực (như tất cả các thông tin của bạn sẽ có), nhưng bạn không nhất thiết muốn kết nối được lưu trong bộ nhớ cache trong quá trình thực thi tập lệnh. Nếu bạn quyết định làm theo cách này, bạn cần chuyển thuộc tính vào Database phương thức khởi tạo.

try {
  // Set ATTR_PERSISTENT in the constructor:
  parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS, array(PDO::ATTR_PERSISTENT => true));
  $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
}

Tài liệu liên quan có tại đây: http://php.net/manual /en/pdo.connections.php#example-950

Giải pháp Singleton:

Sử dụng một mẫu singleton (cũng không được khuyến nghị), ít nhất bạn có thể giảm điều này thành một tìm kiếm / thay thế trong mã mô hình. Cơ sở dữ liệu Database lớp cần một thuộc tính tĩnh để giữ kết nối cho chính nó. Sau đó, các mô hình gọi Database::getInstance() thay vì new Database() để lấy lại kết nối. Bạn sẽ cần thực hiện tìm kiếm và thay thế trong Mã mô hình để thay thế Database::getInstance() .

Mặc dù nó hoạt động tốt và không khó triển khai, nhưng trong trường hợp của bạn, việc kiểm tra sẽ khó khăn hơn một chút vì bạn sẽ phải thay thế toàn bộ Database lớp với một lớp thử nghiệm cùng tên. Bạn không thể dễ dàng thay thế một lớp thử nghiệm trên cơ sở từng trường hợp.

Áp dụng mẫu singleton cho Database :

Lớp
class Database extends PDO{
   // Private $connection property, static
   private static $connection;

   // Normally a singleton would necessitate a private constructor
   // but you can't make this private while the PDO 
   // base class exposes it as public
   public function __construct(){
        try {
            parent::__construct(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
            $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES 'utf8'");
        } catch(PDOException $e){
            Logger::newMessage($e);
            logger::customErrorMsg();
        }

    }

   // public getInstance() returns existing or creates new connection
   public static function getInstance() {
     // Create the connection if not already created
     if (self::$connection == null) {
        self::$connection = new self();
     } 
     // And return a reference to that connection
     return self::$connection;
   }
}

Bây giờ bạn chỉ cần thay đổi Model mã để sử dụng Database::getInstance() :

class Model {
    
  protected $_db;
    
   public function __construct(){
     // Retrieve the database singleton
     $this->_db = Database::getInstance();
   }
}



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL:Tại sao Đặt hàng theo ID chạy chậm hơn nhiều so với Đặt hàng theo các cột khác?

  2. Entity Framework:ánh xạ varchar tới thuộc tính DateTime

  3. Lỗi MySQL:Giá trị nằm ngoài phạm vi cho cột 'số tiền' ở hàng 1

  4. GlassFish 5 và Trình kết nối MySQL

  5. Đôi khi kết nối bị treo với Amazon RDS MySQL &Play Framework 1.2.5 (cài đặt mặc định c3p0)