Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да коригирате Съобщение:SQLSTATE[08004] [1040] Твърде много връзки

Тъй като вашият Model class създава нова Database обект в неговия конструктор, всеки път, когато инстанцирате Model (или който и да е клас, който го разширява), всъщност отваряте нов връзка с базата данни. Ако създадете няколко Model обекти, всеки след това има своя собствена независима връзка с базата данни, която е необичайна, обикновено ненужна, не използва добре ресурсите, но също така активно е вредна, тъй като е използвала всички налични връзки на сървъра.

Например, цикъл за създаване на масив от Model обекти:

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

Използване на инжектиране на зависимост:

Решението е да използвате инжектиране на зависимост и пропускане Database обект в Model::__construct() вместо да му позволите да създаде своя собствена.

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

За да го използвате тогава, управляващият код (кодът, който ще инстанцира вашите модели) трябва сам да извика new Database() само веднъж. След това този обект, създаден от управляващия код, трябва да бъде предаден на конструкторите на всички модели.

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

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

За случая на използване, когато всъщност се нуждаете от различна независима връзка с база данни за модел, можете да му предоставите различна. По-специално, това е полезно за тестване . Можете да замените обект на тестова база данни или фалшив обект.

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

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

Постоянни връзки:

Както бе споменато в коментарите, използването на постоянна връзка е вероятно решение, но не решението, което бих препоръчал . PDO ще се опита да използва повторно съществуваща връзка със същите идентификационни данни (както всички ваши ще имат), но не е задължително да искате връзката да се кешира при изпълнение на скрипта. Ако все пак сте решили да го направите по този начин, трябва да предадете атрибута на Database конструктор.

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

Съответната документация е тук:http://php.net/manual /bg/pdo.connections.php#example-950

Единично решение:

Използвайки единичен модел (също не се препоръчва), можете поне да намалите това до търсене/замяна в кода на модела. Database класът се нуждае от статично свойство, за да запази връзка за себе си. След това моделите извикват Database::getInstance() вместо new Database() за да извлечете връзката. Ще трябва да направите търсене и да замените в кода на модела, за да замените Database::getInstance() .

Въпреки че работи добре и не е труден за внедряване, във вашия случай ще направи тестването малко по-трудно, тъй като ще трябва да замените цялата Database клас с тестов клас със същото име. Не можете лесно да замените тестов клас на база екземпляр по екземпляр.

Прилагане на единичен модел към 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;
   }
}

Сега ще трябва да промените само Model код за използване на 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. Съхранявайте всички промени в данните с всички подробности (като Stackoverflow)

  2. Рекурсивна MySQL заявка?

  3. PDO::заявка срещу PDOStatement::execute (PHP и MySQL)

  4. Как да получа изходни параметри от съхранената процедура на MySQL в Rails?

  5. Как е получена тази логика на записите/разклоненията за случая без статистически данни в MySQL Query Planner?