Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Cara memperbaiki Pesan:SQLSTATE[08004] [1040] Terlalu banyak koneksi

Karena Model your Anda class membuat Database baru objek di konstruktornya, setiap kali Anda membuat Model (atau kelas apa pun yang memperluasnya), Anda sebenarnya membuka baru koneksi basis data. Jika Anda membuat beberapa Model objek, masing-masing kemudian memiliki koneksi database independennya sendiri, yang jarang terjadi, biasanya tidak diperlukan, bukan penggunaan sumber daya yang baik, tetapi juga berbahaya secara aktif karena telah menghabiskan semua koneksi server yang tersedia.

Misalnya, perulangan untuk membuat larik Model objek:

// 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)

Gunakan injeksi ketergantungan:

Solusinya adalah dengan menggunakan injeksi ketergantungan dan lulus Database objek ke dalam Model::__construct() daripada membiarkannya membuat instance-nya sendiri.

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

Untuk menggunakannya, kode pengontrol (kode yang akan membuat instance model Anda) harus memanggil sendiri new Database() hanya sekali. Objek yang dibuat oleh kode pengontrol kemudian harus diteruskan ke konstruktor semua model.

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

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

Untuk kasus penggunaan di mana Anda benar-benar membutuhkan koneksi database independen yang berbeda untuk suatu model, Anda dapat memberikannya yang berbeda. Secara khusus, ini berguna untuk pengujian . Anda dapat mengganti objek database pengujian, atau objek tiruan.

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

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

Koneksi persisten:

Seperti yang disebutkan dalam komentar, menggunakan koneksi persisten mungkin merupakan solusi, tetapi bukan solusi yang saya rekomendasikan . PDO akan mencoba untuk menggunakan kembali koneksi yang ada dengan kredensial yang sama (seperti semua milik Anda), tetapi Anda tidak perlu ingin koneksi di-cache di seluruh eksekusi skrip. Jika Anda memutuskan untuk melakukannya dengan cara ini, Anda harus meneruskan atribut ke Database konstruktor.

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'");
}

Dokumentasi yang relevan ada di sini:http://php.net/manual /en/pdo.connections.php#example-950

Solusi tunggal:

Menggunakan pola tunggal (juga tidak disarankan), Anda setidaknya bisa mengurangi ini menjadi pencarian/penggantian dalam kode model. Database kelas membutuhkan properti statis untuk menjaga koneksi untuk dirinya sendiri. Model kemudian memanggil Database::getInstance() alih-alih new Database() untuk mengambil koneksi. Anda perlu melakukan pencarian dan mengganti kode Model untuk menggantikan Database::getInstance() .

Meskipun bekerja dengan baik dan tidak sulit untuk diimplementasikan, dalam kasus Anda itu akan membuat pengujian sedikit lebih sulit karena Anda harus mengganti seluruh Database kelas dengan kelas pengujian dengan nama yang sama. Anda tidak dapat dengan mudah mengganti kelas pengujian berdasarkan instance demi instance.

Terapkan pola tunggal ke Database :

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

Sekarang Anda hanya perlu mengubah Model kode untuk menggunakan 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. Kinerja Batas MySQL

  2. Python mengimpor kesalahan MySQLdb - Mac 10.6

  3. Bisakah tabel database tanpa kunci utama?

  4. Hapus baris X pertama dari database

  5. Kebocoran Memori Java MySQL JDBC