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 :

PDO et transactions [PDO]


Sujet :

PHP & Base de données

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert Avatar de Madfrix
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    2 326
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 326
    Par défaut PDO et transactions
    Bonjour,

    ma question est simple : est il possible de mettre en place un système de transactions avec un objet PDOStatement ? Autrement dit : est il possible de mettre en place un système de transactions avec prepare() et execute() ? Aucun soucis avec exec() mais je veux utiliser les requetes préparées

    Merci

  2. #2
    Membre Expert Avatar de Madfrix
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    2 326
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 326
    Par défaut
    Problème résolu par ma classe suivante :

    Code php : 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
    65
    66
    67
     
    define('SERVER', 'localhost');
    define('BASE', 'palmares');
    define('USER', 'root');
    define('PWD', '');
     
    class Test2 extends PDO{
     
    	private static $_connexion;
    	private static $_tabRequete = array();
     
    	public static function getInstance(){
     
    		if(!isset(self::$_connexion)){
    			try{
    				self::$_connexion = new PDO('mysql:host='.SERVER.';dbname='.BASE, USER, PWD);
    			}catch(PDOEception $e){
    				die($e);
    			}
    		}
     
    		return self::$_connexion;
     
    	}
     
    	public static function addRequete($requete){
     
    		self::$_tabRequete[] = $requete;
     
    	}
     
    	public static function doRequetes(){
     
    		if(empty(self::$_tabRequete))
    			return null;
     
    		self::$_connexion->beginTransaction();
     
    		foreach(self::$_tabRequete as $requete){
     
    			if(($statement = self::$_connexion->prepare($requete)) === false){
    				self::transactionRollback();
    				return null;
    			}
     
    			if($statement->execute() === false){
    				self::transactionRollback();
    				return null;
    			}
     
    		}
     
    		self::transactionCommit();
     
    	}
     
    	public static function transactionRollback(){
    		self::$_connexion->rollback();
    		self::$_tabRequete = array();
    	}
     
    	public static function transactionCommit(){
    		self::$_connexion->commit();
    		self::$_tabRequete = array();
    	}
     
    }


    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // --- on crée une instance de connexion
    TEST2::getInstance();
     
    // --- on ajoute des requetes à la transaction
    TEST2::addRequete('UPDATE cotations SET variation=10 WHERE cotation_id=125905');
    TEST2::addRequete('UPDATE cotations SET variation=20 WHERE cotation_id=125905');
     
    // --- On execute les requetes
    TEST2::doRequetes();
    -> transaction correctement effectuée

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // --- on crée une instance de connexion
    TEST2::getInstance();
    
    // --- on ajoute des requetes à la transaction
    TEST2::addRequete('UPDATE cotations SET variation=10 WHERE cotation_id=125905');
    TEST2::addRequete('UPDATE cotations SET vaariation=20 WHERE cotation_id=125905');
    
    // --- On execute les requetes
    TEST2::doRequetes();
    -> transaction non effectuée

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    625
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 625
    Par défaut
    Hello,

    Oui c'est tout à fait possible.

    Voici un exemple de test :
    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
    <?php
    $pdo = new PDO( 'mysql:host=127.0.0.1;dbname=test' , 'root' , '' );
    $pdo->setAttribute( PDO::ATTR_ERRMODE , PDO::ERRMODE_EXCEPTION );
     
    $val = 0;
    $stmt = $pdo->prepare( 'INSERT INTO test2 (valeur) VALUES ( :val )');
    $stmt->bindParam( ':val' , $val , PDO::PARAM_INT );
    try{
    	$pdo->beginTransaction();
    	for( $i = 0 ; $i < 10 ; $i++ ){
    		$val++;
    		if( $i == 4 ) $pdo->query( 'kloug !' ); // on fait planter le script de manière élégante :)
    		$stmt->execute();
    	}
    	$pdo->commit();
    }
    catch( Exception $e ){
    	$pdo->rollback();
    	echo 'erreur ' . $e->getMessage() . "\n";
    }
    Avec transaction, rien n'est inséré. Sans transaction, 4 lignes seront insérées (boucle 0 à 3).

  4. #4
    Membre Expert Avatar de Madfrix
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    2 326
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 326
    Par défaut
    Elle l'eau

    J'avais tenté quelque chose comme cela mais ca ne marchait pas avec try. J'en avais conclu que le try ne catchait pas les false et j'avais donc testé avec les if...=== false et là ca marrchait :

    Initialement:
    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
     
    public static function doRequetes(){
     
    		if(empty(self::$_tabRequete))
    			return null;
     
    		self::$_connexion->beginTransaction();
     
    		foreach(self::$_tabRequete as $requete){
     
    			try{
    				$statement = self::$_connexion->prepare($requete);
    				$statement->execute();
    			}catch(PDOException $e){
    				self::transactionRollback();
    			}
     
    		}
     
    		self::transactionCommit();
     
    	}
    -> marchait pas, requetes partiellement exécutées

    Maintenant:
    Code php : 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
     
    public static function doRequetes(){
     
    		if(empty(self::$_tabRequete))
    			return null;
     
    		self::$_connexion->beginTransaction();
     
    		foreach(self::$_tabRequete as $requete){
     
    			if(($statement = self::$_connexion->prepare($requete)) === false){
    				self::transactionRollback();
    				return null;
    			}
     
    			if($statement->execute() === false){
    				self::transactionRollback();
    				return null;
    			}
     
    		}
     
    		self::transactionCommit();
     
    	}
    ->marche

    Ce que j'arrive pas à comprendre c'est que mon catch saisi pas l'erreur (false) de mon execute()


    PS: je cherchais à faire des transactions uniquement avec prepare() non avec query() ni exec()

  5. #5
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    Salut

    Je suis plutôt d'avis de la méthode de Petibidon, c'est à dire que le try/catch soit dans la page et non dans la classe.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    $pdo->addRequete('the requete');
    $pdo->beginTransaction();
    try {
    	$pdo->doRequetes();
    	$pdo->transactionCommit();
    }
    catch (Exception $e) {
    	$pdo->transactionRollback();
    	echo 'Erreur : '.$e->getMessage();
    }
    Du coup, et théoriquement, tu peux lancer ta propre exception au niveau de la classe.
    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
     
    public static function doRequetes() {
    	if(empty(self::$_tabRequete)) return null;
     
    	foreach(self::$_tabRequete as $requete) {
    		if (($statement = self::$_connexion->prepare($requete)) === false) {
    			throw new Exception('Un problème sur le prepare');
    		}
     
    		if ($statement->execute() === false) {
    			throw new Exception('Un problème sur le excecute');
    		}
     
    	}
    }
    C'est un pure exemple, mais théoriquement si on spécifie à PDO de lancer des exceptions (le setAttribut(... ERRMODE_EXCEPTION), une erreur sur les méthodes prepare/execute devrait provoquer une exception, ce qui veut dire qu'il ne serait pas nécessaire de rajouter de throw new ...
    ( Qui devrait être attrapée par le try/catch plus haut )

  6. #6
    Membre Expert Avatar de Madfrix
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    2 326
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 326
    Par défaut
    Citation Envoyé par RunCodePhp Voir le message
    Je suis plutôt d'avis de la méthode de Petibidon, c'est à dire que le try/catch soit dans la page et non dans la classe.
    Bonjour,

    ok je vais étudier cette possibilité mais qu'apporte t-elle en plus ? Moins de rigidité de code ? Plus d'évolutivité ?

    Merci

  7. #7
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    Disons que j'étais intervenu dans le seul but de donner un exemple dans le but d'exploiter les exceptions suivi d'un try/catch.
    Faut voir si c'était ton but aussi.

    PDO d'ailleurs est d'ailleurs une des rares classe proposant de gérer nativement les exceptions (PDOException), du coup, je trouve dommage de ne pas l'exploiter.
    Pour pouvoir l'exploiter, c'est à dire que pour "attraper" une exception il faut au moins définir à PDO de lancer les exceptions si le cas se présente : setAttribut(PDO::ERROR_MODE, PDO::ERROR_EXCEPTION)
    C'est peut être pour ça que tu n'as rien remarqué de particulier dans le try/catch.

    Après, à chacun de gérer l'exception.
    Soit se contenter de voir le message tel qu'il est affiché par défaut. Donc pas de try/catch
    Soit de l'attraper par un try/catch, et gérer l'erreur.

    Pour se qui est de plus ou moins de rigidité, ça dépend du comment on gère l'exception, c'est au cas par cas. Du coup, il me semble difficile de dire si c'est plus ou moins rigide de procéder ainsi.
    Je dirais que ça offre plus de souplesse.


    Ceci dit, je ne suis pas super calé sur ce point.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [PDO] Transaction PDO mysql
    Par chat de nuit dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 25/10/2011, 16h33
  2. [MySQL] php pdo Transactions
    Par watibou dans le forum PHP & Base de données
    Réponses: 0
    Dernier message: 03/09/2010, 14h59
  3. [PDO] Transaction PDO inactive
    Par albedo0 dans le forum PHP & Base de données
    Réponses: 10
    Dernier message: 06/07/2010, 20h40
  4. [PDO] PDO/MYSQL: les transactions?
    Par Helfima dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 21/04/2009, 10h04
  5. Apropos des Transactions au sein d'un Stored Procedure
    Par Sarbacane dans le forum Connexion aux bases de données
    Réponses: 6
    Dernier message: 16/11/2004, 08h21

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