Dans les volets précédents, nous avons vu les bases des transactions, leur rôle, les systèmes qui les supportent, et comment les implémenter.
Mais dans les vraies applications, surtout à grande échelle, les choses se compliquent :
tu risques de rencontrer des erreurs subtiles, des blocages (deadlocks), ou des performances dégradées.
👉 Ce volet est donc dédié à la gestion avancée des transactions.
🔁 1. Gérer les erreurs dans une transaction
Les erreurs peuvent provenir de multiples sources pendant une transaction :
- ❌ Problème de validation métier
- ❌ Conflit avec une autre transaction (concurrence)
- ❌ Échec de connexion à un service tiers
- ❌ Requête SQL mal formée ou contrainte violée (clé étrangère, unique…)
💡 Que faire ?
Toujours encapsuler les transactions dans un bloc try/catch
, surtout quand elles sont critiques :
try { DB::beginTransaction(); // ... opérations critiques DB::commit();} catch (\Throwable $e) { DB::rollBack(); Log::error("Transaction failed: " . $e->getMessage()); throw $e;}
🚨 N'oublie pas de relancer l'exception si elle doit remonter au frontend ou à un service.
💥 2. Comprendre et éviter les deadlocks
❓ C’est quoi un deadlock ?
Un deadlock (verrou mortel) survient lorsque deux transactions s’attendent mutuellement pour libérer une ressource. Résultat : elles restent bloquées l’une l’autre indéfiniment (ou jusqu'à l’intervention du moteur SQL).
🔍 Exemple typique :
- Transaction A verrouille la ligne X
- Transaction B verrouille la ligne Y
- A veut modifier Y (verrouillé par B)
- B veut modifier X (verrouillé par A) ➡️ Blocage mutuel !
⚠️ Symptôme dans Laravel
Tu peux voir une erreur comme :
SQLSTATE[40001]: Deadlock found when trying to get lock; try restarting transaction
🛠️ Comment éviter les deadlocks ?
✔️ 1. Toujours accéder aux ressources dans le même ordre
Par exemple, si tu modifies deux tables ensemble (users et orders), modifie-les toujours dans le même ordre, quelle que soit la requête.
// Mauvais$repo->updateOrder($id);$repo->updateUser($userId); // Bon (toujours dans cet ordre)$repo->updateUser($userId);$repo->updateOrder($id);
✔️ 2. Gérer la concurrence avec des LOCK
Pour des opérations critiques, tu peux verrouiller explicitement :
DB::table('accounts')->where('id', $id)->lockForUpdate()->first();
✔️ 3. Limiter la durée des transactions
Plus une transaction est longue, plus elle a de chances de causer un deadlock ou un blocage.
❌ Ne fais pas de requête API, de traitement lourd ou de logique métier trop complexe à l'intérieur d’une transaction.
✔️ 3. Limiter la durée des transactions
Plus une transaction est longue, plus elle a de chances de causer un deadlock ou un blocage.
❌ Ne fais pas de requête API, de traitement lourd ou de logique métier trop complexe à l'intérieur d’une transaction.
DB::transaction(function () { // ...}, $attempts = 5);
Cela réessaye automatiquement en cas de deadlock !
🧠 3. Optimiser les performances des transactions
⚡ 1. Ne verrouille que ce qui est nécessaire
Évite les SELECT * ou les mises à jour massives. Préfère cibler les lignes exactes, pour que les verrous soient plus petits et relâchés plus vite.
// MieuxDB::table('users')->where('id', $id)->update(['status' => 'active']);
⚡ 2. Indexe correctement les colonnes utilisées dans WHERE
Des requêtes lentes = des verrous longs = des risques de blocage.
🚀 Indices = vitesse + moins de conflits
⚡ 3. Préfère les transactions courtes
Découpe les traitements complexes :
// MauvaisDB::transaction(function () { // boucle lente + logique + notifications + update}); // Mieux : séparer$data = collect([...])->map(...);DB::transaction(function () use ($data) { foreach ($data as $item) { // update simple }});
📊 4. Benchmarks : Quel SGBD est le plus performant ?
SGBD | Gestion des deadlocks | Performance transactionnelle | Recommandé pour |
---|---|---|---|
MySQL | Bonne (InnoDB) | Très rapide | Web apps courantes |
PostgreSQL | Excellente (MVCC) | Très stable et cohérente | Applications métier |
SQL Server | Très solide | Optimisé pour gros volumes | Apps d’entreprise |
📌 Laravel fonctionne parfaitement avec les trois !
✅ Résumé : bonnes pratiques à retenir
- Toujours capturer les erreurs dans une transaction
- Attention aux deadlocks : ordre des accès, verrou explicite, retries
- Optimise les accès : index, portée réduite, durée courte
- Teste les comportements en charge ou en cas de conflit