Utiliser le rollback dans MySQL au cas ou une requête échoue partiellement

Pourquoi effectuer un rollback en cas d’erreur SQL ?

Récemment j’ai eu une gêne lors de mon développement : j’avais une requête qui devait insérer dans deux tables des informations, mais la seconde requêtes échouait souvent car le code n’était pas bon. Il fallait à chaque fois que j’efface les données insérées dans la première table.

C’est alors qu’est venue l’idée de faire du transactionnel. C’est quoi une requête transactionnelle? C’est une requête que l’on peut inverser si quelque chose ne se passe pas comme prévu, cela s’appelle un ROLLBACK.

Par défaut dans MySQL, les requêtes ne sont pas transactionnelle, on ne peut pas revenir en arrière, car l’autocommit est activé. Un COMMIT c’est quoi? c’est le fait de valider une requête SQL.

Donc pour faire une requête transactionnelle, il faut désactiver l’AUTOCOMMIT le temps de la requête.

Les raisons de faire des requêtes transactionnelles

Lorsque l’on manipule une base de données relationnelle, les transactions sont essentielles pour garantir l’intégrité des données. Une transaction regroupe plusieurs opérations SQL qui doivent être exécutées comme une unité indivisible : soit toutes les opérations réussissent, soit aucune n’est appliquée. Si une erreur survient en cours d’exécution, effectuer un rollback (retour à l’état précédent) est crucial.

Prenons comme exemple la fonction importUsers présentée ci-dessus. Elle illustre un scénario classique où plusieurs opérations SQL sont imbriquées :

  1. Insertion de nouveaux utilisateurs dans la table utilisateurs : Cette première opération insère les données personnelles des utilisateurs (prénom, nom, email, etc.).
  2. Association des utilisateurs à leurs groupes dans la table utilisateur_groupe : Une fois les utilisateurs créés, ils sont liés à des groupes prédéfinis via une deuxième opération SQL.

Une transaction SQL encadre ces deux étapes afin qu’aucune donnée incohérente ne soit enregistrée si un problème survient. Le code pour le farie est le suivant :

function importUsers($pdo, $users)
{
    $insertedIds = [];

    $pdo->beginTransaction();

Les risques sans rollback

Si le rollback n’est pas correctement implémenté, plusieurs problèmes peuvent apparaître :

  • Incohérence des données : Supposons que la première opération (insertion dans utilisateurs) réussisse, mais que la seconde (liaison avec utilisateur_groupe) échoue. Les utilisateurs seront présents dans la base, mais sans lien avec leurs groupes, ce qui pourrait perturber les fonctionnalités de l’application.
  • Perte de confiance dans le système : Des erreurs de ce type peuvent miner la crédibilité du système aux yeux des utilisateurs ou de l’équipe technique.
  • Problèmes de maintenance : Identifier et corriger ces incohérences peut être complexe et coûteux en temps.

Le rôle de try-catch et du rollback

La fonction importUsers utilise un bloc try-catch pour lever une exception en cas de problème. En cas d’exception, le rollback annule toutes les opérations de la transaction et remet la base à son état initial. Pratique non? plus besoin d’effacer à la main les données !

try {
        // table utilisateur
        foreach ($users as $user) {
            //separate the items of csv
            $user = explode(',', $user);
            $sql = "INSERT INTO utilisateurs (firstname, lastname, email, password, role,groupe) 
        VALUES (:nom, :prenom, :email, :mdp,:role,:groupe)";
            $params = [
                'nom' => $user[0],
                'prenom' => $user[1],
                'email' => $user[2],
                'mdp' => 'mdp', // generate password
                'role' => STUDENT,
                'groupe' => $user[4],
            ];
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);
            $tmpArray = [
                'id' => $pdo->lastInsertId(),
                'groupe' => $user[4]
            ];
            $insertedIds[] = $tmpArray;
        }

Rappelons les étapes principale :

  • Début de la transaction : La méthode $pdo->beginTransaction() initialise une transaction.
  • Exécution des opérations : Les opérations SQL sont effectuées dans le cadre de cette transaction dans le try
  • Gestion des erreurs : Si une exception est levée, le rollback est exécuté via $pdo->rollBack().
  • Validation des modifications : Si toutes les opérations réussissent, la transaction est validée avec $pdo->commit().

Pas la peine d’utiliser un if car le catch fait office de if.

        // les groupes sont créés séparément
        // raccorder les utilisateur à table utilisateur groupe
        foreach ($insertedIds as $user) {
            $sql = "INSERT INTO utilisateur_groupe (utilisateur_id, groupe_id) VALUES (:utilisateur_id, :groupe_id)";
            $params = [
                'utilisateur_id' => $user['id'],
                'groupe_id' => $user['groupe'],
            ];
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);
        }
    } catch (Exception $e) {
        $pdo->rollBack();
        echo 'error : ' . $e . PHP_EOL;
        return false;
    }
    $pdo->commit();
    return true;
}

Regardez comment le COMMIT est placé en dehors du bloc catch, alors que le ROLLBACK est dans le bloc catch.

Avantages d’utiliser un rollback

  1. Intégrité des données : Les transactions assurent qu’aucune opération partiellement réussie n’impacte la base de données.
  2. Fiabilité : En annulant toutes les modifications en cas d’erreur, le système devient plus robuste.
  3. Facilité de maintenance :Au prix d’un complexité accrue, les développeurs sont moins embêtés.

Conclusion

L’utilisation des transactions SQL et du rollback est une pratique essentielle pour garantir la stabilité des applications manipulant des bases de données. La fonction ci dessus en est un excellent exemple. En regroupant les opérations critiques dans une transaction et en prévoyant un rollback en cas d’erreur, on s’assure que les données restent cohérentes et fiables, même si à la base c’est utilisé en production, je m’en sers surtout ici pour le développement ! Car heureusement en production il est rare que cela se produise.

Retour en haut