sql >> Database teknologi >  >> RDS >> Mysql

Sådan rettes Meddelelse:SQLSTATE[08004] [1040] For mange forbindelser

Fordi din Model klasse instansierer en ny Database objekt i dets konstruktør, hver gang du instansierer en Model (eller en hvilken som helst klasse, der udvider den), åbner du faktisk en ny database forbindelse. Hvis du opretter flere Model objekter, har hver så sin egen uafhængige databaseforbindelse, hvilket er ualmindeligt, normalt unødvendigt, ikke en god brug af ressourcer, men også aktivt skadeligt, da det har brugt alle serverens tilgængelige forbindelser.

For eksempel looping for at skabe en matrix af Model objekter:

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

Brug afhængighedsinjektion:

Løsningen er at bruge afhængighedsinjektion og pass Database objekt ind i Model::__construct() i stedet for at tillade den at instansiere sin egen.

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

For at bruge det derefter, bør den kontrollerende kode (koden, som vil instansiere dine modeller) selv kalde new Database() kun én gang. Det objekt, der er oprettet af den kontrollerende kode, skal derefter videregives til konstruktørerne af alle modeller.

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

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

I det tilfælde, hvor du faktisk har brug for en anden uafhængig databaseforbindelse til en model, kan du give den en anden. Dette er især nyttigt til test . Du kan erstatte et testdatabaseobjekt eller et falsk objekt.

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

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

Vedholdende forbindelser:

Som nævnt i kommentarerne er brug af en vedvarende forbindelse muligvis en løsning, men ikke den løsning, jeg vil anbefale . PDO vil forsøge at genbruge en eksisterende forbindelse med de samme legitimationsoplysninger (som alle dine vil have), men du ønsker ikke nødvendigvis, at forbindelsen skal cachelagres på tværs af scriptudførelse. Hvis du besluttede dig for at gøre det på denne måde, skal du videregive attributten til Database konstruktør.

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

Den relevante dokumentation er her:http://php.net/manual /da/pdo.connections.php#example-950

Singleton-løsning:

Ved at bruge et singleton-mønster (også ikke anbefalet), kan du i det mindste reducere dette til en søgning/erstatning i modelkoden. Database klasse har brug for en statisk egenskab for at holde en forbindelse for sig selv. Modeller kalder derefter Database::getInstance() i stedet for new Database() for at hente forbindelsen. Du skal søge og erstatte modelkoden for at erstatte Database::getInstance() .

Selvom det fungerer godt og ikke er svært at implementere, ville det i dit tilfælde gøre testningen lidt sværere, da du skulle erstatte hele Database klasse med en testklasse af samme navn. Du kan ikke nemt erstatte en testklasse fra instans til instans.

Anvend singleton-mønster på 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;
   }
}

Nu skal du kun ændre Model kode for at bruge Database::getInstance() :

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



  1. json_encode for mysql-forespørgsel returnerer nogle null-kolonner i nogle rækker, men kolonnerne er ikke null

  2. 3 måder at finde positionen af ​​en understreng i en streng i MySQL

  3. Sådan opretter du en udvidelse til SSMS 2019 (v18)

  4. SQL-forespørgsel til at oversætte en liste over tal, der matches mod flere intervaller, til en liste med værdier