Gestion des transactions avec PDO

Problème

Une série de requêtes SQL sont logiquement liées entre elles et on voudrait qu’elles soient toutes exécutées ou aucune. En effet dans certains cas, la prise en compte d’une partie des requêtes seulement peut conduire à une incohérence dans le système d’information. La base de données peut ainsi être corrompue et très difficile à rectifier par la suite. Par exemple, si on a 2 requêtes qui se suivent et qui sont liées:

<?php
  require 'connexion.php';
  $connexion=connect_bd();

  $stmt1 = $pdo->prepare('
      UPDATE compte
      SET solde = solde - :montant
      WHERE nom = :nom
  ');
  $stmt2 = $pdo->prepare('
      UPDATE compte
      SET solde = solde + :montant
      WHERE nom = :nom
  ');

  // Retrait du Compte1
  $cpte1 = 'Compte1';
  $montant = 50;
  $stmt1->bindParam(':nom', $cpte1);
  $stmt1->bindParam(':solde', $montant, PDO::PARAM_INT);
  $stmt1->execute();

  // Credit du Compte2
  $cpte2 = 'Compte2';
  $depot = 50;
  $stmt2->bindParam(':nom', $cpte2);
  $stmt->bindParam(':montant', $depot, PDO::PARAM_INT);
  $stmt->execute();
?>

Ceci peut conduire à un problème en cas d’interruption de cette séquence. En particulier le Compte1 peut avoir été débité sans que le Compte2 soit crédité.

On peut résoudre cette fragilité en utilisant une transaction:

<?php
  require 'connexion.php';
  $connexion=connect_bd();

  $stmt1 = $connexion->prepare('
      UPDATE compte
      SET solde = solde - :solde
      WHERE nom = :nom
  ');
  $stmt2 = $connexion->prepare('
      UPDATE compte
      SET solde = solde + :montant
      WHERE nom = :nom
  ');

  // On commence la transaction
  $connexion ->beginTransaction()
  // Retrait du Compte1
  $cpte1 = 'Compte1';
  $montant = 100;
  $stmt1->bindParam(':nom', $cpte1);
  $stmt1->bindParam(':solde', $montant, PDO::PARAM_INT);
  $stmt1->execute();

  // Credit du Compte2
  $cpte2 = 'Compte2';
  $depot = 50;
  $stmt2->bindParam(':nom', $cpte2);
  $stmt->bindParam(':montant', $depot, PDO::PARAM_INT);
  $stmt->execute();
  //on termine la transaction
  $connexion -> commit();
?>

Si la séquence échoue, PDO commandera un RollBack automatique, c’est à dire une annulation de toute la transaction.

Connexion persistante avec PDO

Pour créer une connexion persistante avec PDO, il suffit d’utiliser l’attribut ATTR PERSISTENT à l’instanciation de l’objet PDO. Lors des appels ultérieurs, si les paramètres de création sont identiques, l’objet déjà créé sera simplement réutilisé.

<?php
function connect_db()
{
  $dsn="mysql:dbname=".BASE.";host=".SERVER;
  try
  {
      $connexion=new PDO($dsn,USER,PASSWD,
          array(PDO::ATTR_PERSISTENT =>true));
  }
  catch(PDOException $e)
  {
      printf("Échec de la connexion : %s\n", $e->getMessage());
      exit();
  }
  return $connexion;
}
?>