IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PHP & Base de données Discussion :

Gérer les connexions PDO


Sujet :

PHP & Base de données

  1. #1
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 273
    Points : 152
    Points
    152
    Par défaut Gérer les connexions PDO
    Bonsoir,

    Afin de gérer les requêtes SQL sur mon site j'utilise PDO.

    Afin que la page sache comment se connecter, j'ai un fichier unique avec la connexion à l'ensemble des bases de données, par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    try {
        $strConnection = 'mysql:host=localhost;dbname=BaseDeDonnee1'; //Ligne 1
        $arrExtraParam= array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"); //Ligne 2
        $pdo_gamedata1 = new PDO($strConnection, 'IdentifiantMySql1', 'motdepasse', $arrExtraParam); //Ligne 3; Instancie la connexion
        $pdo_gamedata1->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);//Ligne 4
    }
    catch(PDOException $e) {
        echo 'Erreur lors de la connexion';
    }
     
    try {
        $strConnection = 'mysql:host=localhost;dbname=BaseDeDonnee2'; //Ligne 1
        $arrExtraParam= array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"); //Ligne 2
        $pdo_gamedata2 = new PDO($strConnection, 'IdentifiantMySql2', 'motdepasse', $arrExtraParam); //Ligne 3; Instancie la connexion
        $pdo_gamedata2->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);//Ligne 4
    }
    catch(PDOException $e) {
        echo 'Erreur lors de la connexion';
    }
    Ensuite sur la page je fais par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    <?php
    include ('connexion.php');
    try 
    {
    $req_rechercher_nombre_paiements = $pdo_gamedata1->prepare('SELECT COUNT(*) FROM Historique;');
    $req_rechercher_nombre_paiements->execute();
    $resultats_rechercher_nombre_paiements = $req_rechercher_nombre_paiements->fetchAll();
    } 
    catch (Exception $e) { }
     
    echo "Il y a ".$resultats_rechercher_nombre_paiements[0][0]." résultats.";
    ?>
    Cela fonctionne parfaitement, mais j'ai plusieurs questions:
    - Est ce que la connexion pdo_gamedata1 reste ouverte après l'exécution de la requête ?
    - Est ce qu'une visite sur la page PHP qui contient la requête va établir 1 ou 2 connexions SQL ? Les 2 se trouvent dans le fichier ajouté avec l'include, mais seule les informations contenues dans pdo_gamedata1 sont utilisés.

    J'ai fais ce fichier unique afin de pouvoir facilement le modifier et que ça s'applique d'un coup sur l'ensemble des pages. Si mettre l'ensemble des informations dans un même fichier provoque l'ouverture de toutes les connexions dont les informations sont contenues dans le fichier même si je ne fais pas de requête SQL, c'est très problématique, par exemple si l'hébergeur limite les connexions à 50 en simultanée. En effet, si dans mon fichier ajouté avec l'include se trouvent les informations de connexion à 5 bases de données du site, il suffirait que 10 personnes se rendent sur une page PHP qui contient cet include afin d'utiliser la totalité des connexions autorisées.

    Dans l'attente d'une réponse afin de discuter de ma gestion des connexions, je vous souhaite de passer une agréable soirée.

  2. #2
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Salut,

    Depuis quelques années déjà tu peux mettre le charset dans la chaine de connexion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $connexion1 = 'mysql:host=localhost;dbname=BaseDeDonnee1;charset=utf8';
    Il est pratique de créer un singleton pour les connexions à la bdd ce qui permet de s'assurer qu'une seule connexion sera créée même si tu appelles plusieurs fois la fonction de connexion dans le script. Pour plusieurs bdd tu peux créer un multiton :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    <?php
    class C_PDO
    {
      private static $instance = [];
     
      private static function new_PDO($db_name) 
      {
    	// le fichier connexions.php contient les identifiants de connexion des bdd : $connexion1, $username1, $pass1, $connexion2, $username2, $pass2
            require_once('connexions.php');
     
    	switch ($db_name)
    	{
    		case "db1" : $connexion = isset($connexion1)? $connexion1 : null;
    			     $username = isset($username1)? $username1 : null;
    		             $pass = isset($pass1)? $pass1 : null;
    			     break;
     
    		case "db2" : $connexion = isset($connexion2)? $connexion2 : null;
    			     $username = isset($username2)? $username2 : null;
    			     $pass = isset($pass2)? $pass2 : null;
    			     break;	
     
    		default: $connexion = null;
    	}
     
            try
    	{
    		if(!(isset($connexion,$username,$pass))) throw new Exception('"'.$db_name.'" identifiants de connexion incomplets.');
     
    		// Options de configuration PDO 
    		$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;		
    		$pdo_options[PDO::ATTR_EMULATE_PREPARES] = false;// Important
     
    		self::$instance[$db_name] = new PDO($connexion, $username, $pass, $pdo_options);	
    	}
    	catch (PDOException $e) // pour gérer les erreur pdo
    	{
    		// Mode debug
    		// exit($e->getMessage());
     
    		// Mode production
    		exit('Problème de connexion '.$db_name);
    	}
    	catch (Exception $e) // pour gérer les autres erreurs (provenant éventuellement ici du throw new Exception)
    	{
    		exit($e->getMessage());
    	} 
      }
     
      public static function getC($db_name) 
      {
        // Si l'instance de connexion à la base de donnees n'existe pas, creation et ajout à la liste des instances
        if( !array_key_exists($db_name, self::$instance) ) 
        {
            self::new_PDO($db_name);
        }    
        return self::$instance[$db_name];
      }
    }
     
    var_dump(C_PDO::getC('db1'));
    var_dump(C_PDO::getC('db2'));
    var_dump(C_PDO::getC('db1'));
    ?>
    Tu peux appeler C_PDO::getC('db1') ou C_PDO::getC('db2') autant de fois que nécessaire mais une seule instance de chaque connexion sera créée pour tout le script. Et si tu ne les appelle pas aucune connexion ne sera faite.

    Les connexions sont fermées automatiquement par php en fin de script (laisser faire php est plus pratique et néanmoins optimisé).

  3. #3
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2011
    Messages : 273
    Points : 152
    Points
    152
    Par défaut
    Bonsoir,

    C'est vraiment le script parfait qui fait exactement ce dont j'avais besoin.

    Cependant, j'ai quelques questions afin d'être certain d'avoir bien compris:

    - Au lieu de faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    try 
    {
    $req_rechercher_nombre_paiements = $pdo_gamedata1->prepare('SELECT COUNT(*) FROM Historique;');
    $req_rechercher_nombre_paiements->execute();
    $resultats_rechercher_nombre_paiements = $req_rechercher_nombre_paiements->fetchAll();
    } 
    catch (Exception $e) { }
    je dois donc faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    try 
    {
    $req_rechercher_nombre_paiements = C_PDO::getC('db1')->prepare('SELECT COUNT(*) FROM Historique;');
    $req_rechercher_nombre_paiements->execute();
    $resultats_rechercher_nombre_paiements = $req_rechercher_nombre_paiements->fetchAll();
    } 
    catch (Exception $e) { }
    ???

    - Donc si j'ai bien compris, avec ma méthode actuelle, l'ensemble des connexions sont ouvertes à chaque chargement de page ?

    - Avec ma méthode actuelle, j'inclus le nom de la base de données dans les informations de connexion. Avec votre script le simple fait de mettre le nom de la base de données entre les parenthèses suffit à indiquer à PHP sur quelle base effectuer la requête ?

    - Selon vous cette méthode peut être ralentir le chargement de plus de 0.3 seconde ? Je pense qu'au delà c'est très visible chez les personnes qui ont une très bonne connexion.

    De plus, il ne risque pas d'y avoir des soucis si je met une requête SQL dans une boucle "for" ? Car d'après ce que j'ai compris, le require_once('connexions.php'); est lancé à chaque appel de C_PDO::getC donc à chaque requête.

    Je vous remercie d'avance pour votre réponse.
    Bonne nuit

  4. #4
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Citation Envoyé par encoremoi21258
    Au lieu de faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $req_rechercher_nombre_paiements = $pdo_gamedata1->prepare('SELECT COUNT(*) FROM Historique;');
    je dois donc faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $req_rechercher_nombre_paiements = C_PDO::getC('db1')->prepare('SELECT COUNT(*) FROM Historique;');
    OUI
    En reprenant ton ancien code et en utilisant la classe de connexion tu pourrais aussi faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $pdo_gamedata1 = C_PDO::getC('db1');
    $req_rechercher_nombre_paiements = $pdo_gamedata1->prepare('SELECT COUNT(*) FROM Historique;');
    Citation Envoyé par encoremoi21258
    Donc si j'ai bien compris, avec ma méthode actuelle, l'ensemble des connexions sont ouvertes à chaque chargement de page ?
    Oui puisque tu les fait sans condition dans tes try dès le chargement de la page (dans ton fichier unique) donc tu ouvrais une connexion à db1 et db2 systématiquement.

    La classe C_PDO remplace ton fichier unique et l'avantage de passer par une classe de connexion (ou une fonction), c'est que la connexion est faite uniquement sur demande quand tu appelles C_PDO::getC('db1') ou C_PDO::getC('db2'). Ensuite l'intérêt supplémentaire de cette classe statique est que tu peux l'appeler plusieurs fois en étant certain qu'une seule connexion pour chaque bdd sera ouverte.

    Cela ne veut pas dire pour autant que ton précédent script ouvrait plusieurs connexions pour chaque bdd si tu utilisais uniquement $pdo_gamedata1 et $pdo_gamedata2. Mais les fonctions sont très pratiques car elles peuvent s'appeler depuis l'intérieur d'une autre fonction ou d'une classe et le fait qu'elles soient statiques te permet de les appeler autant de fois que nécessaire sans te poser de questions.

    Par exemple tu pourrais faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function insert1 ()
    {
        $req_insert = C_PDO::getC('db1')->prepare('INSERT...');
        //...
    } 
     
    function select1 ()
    {
        $req_select1 = C_PDO::getC('db1')->prepare('SELECT...');
        //...
    }
     
    function update1 ()
    {
        $req_selct1 = C_PDO::getC('db1')->prepare('UPDATE...');
        //...
    }
    //...
    même si C_PDO::getC('db1') est appelée plusieurs fois par chacune de ces fonctions, une seule connexion à db1 sera faite pour le script en cours. Après cela crée une injection de dépendance puisque la connexion est inclue dans la fonction sans passer par un paramètre. Mais tu pourrais tout aussi bien la passer en paramètre si tu préfère faire autrement. La fonction statique permet simplement un maximum de souplesse.

    Citation Envoyé par encoremoi21258
    Selon vous cette méthode peut être ralentir le chargement de plus de 0.3 seconde ? Je pense qu'au delà c'est très visible chez les personnes qui ont une très bonne connexion.
    Il n'y aura aucun ralentissement du code, ce que je te propose est simplement plus facile à gérer. Et comme son nom et la doc l'indiquent, le require_once ne sera fait qu'une seule fois. Tu pourrais te passer du require_once en mettant tes identifiants de connexion avant le switch dans la fonction new_PDO($db_name) de la classe C_PDO mais il n'est pas propre de laisser trainer ces données essentielles dans tes scripts, classes ou fonctions, aussi ont les planque souvent dans un fichier inclus dans un dossier protégé par un .htaccess avec la mention deny from all ou sinon dans un dossier situé à l'extérieur de l'arborescence du site.

    Citation Envoyé par encoremoi21258
    De plus, il ne risque pas d'y avoir des soucis si je met une requête SQL dans une boucle "for" ?
    Avec les requêtes préparées tu devrais pouvoir éviter de mettre tes requêtes prepare dans une boucle. Normalement seul le execute() devrait se trouver dans la boucle.

    Enfin même si tu devais mettre l'entièreté de ta requête dans une boucle ce n'est pas un problème pour la connexion puisque comme déjà dit le fait que les fonctions soient statiques te permet de les appeler autant de fois que tu veux - seule la première connexion déjà ouverte sera utilisée - et de plus, comme déjà dit, tu peux aussi bien faire $pdo_gamedata1 = C_PDO::getC('db1'); si tu préfères passer une variable dans ta boucle plutôt que la fonction de connexion. Mais bon pour des raisons de performances assures-toi que tu ne pourrais pas mettre uniquement le execute() dans la boucle, indifféremment du type de connexion que tu utilises.

    Dernière chose, les erreurs pdo se récupèrent avec catch (PDOException $e) et non pas catch (Exception $e). D'ailleurs le code de la classe C_PDO est intéressant dans le sens où il montre aussi comment différencier les erreurs pdo des autres erreurs avec les deux catch successifs

Discussions similaires

  1. Gérer les connexions au Service Web
    Par nanooby dans le forum Services Web
    Réponses: 2
    Dernier message: 25/05/2015, 10h21
  2. Gérer les connexions
    Par MarieKisSlaJoue dans le forum C#
    Réponses: 2
    Dernier message: 07/06/2012, 10h13
  3. Gérer les connexions avec ADO
    Par fold85 dans le forum Access
    Réponses: 17
    Dernier message: 07/01/2009, 16h59
  4. [Connection DB] Bien gérer les connexions !
    Par rad_hass dans le forum C#
    Réponses: 11
    Dernier message: 25/02/2008, 16h44
  5. Comment gérer les problèmes de connexion sur un idFTP ?
    Par giloutho dans le forum Web & réseau
    Réponses: 2
    Dernier message: 05/12/2005, 18h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo