Tutoriels

Comment gérez-vous les problèmes de concurrence d'accès à la base de données ?

Problèmes de concurrence en base de données : dirty read, deadlock, phantom read. Solutions avec isolation, verrouillage, timestamping et cas concrets (réservation, e-commerce).

Introduction

Les bases de données jouent un rôle essentiel dans les systèmes informatiques modernes, supportant des millions d’opérations simultanées chaque jour. Avec des volumes de données croissants et des utilisateurs accédant simultanément aux mêmes ressources, des problèmes de concurrence peuvent survenir. Ces problèmes, tels que les blocages, les conflits de mise à jour ou les lectures incohérentes, peuvent affecter la performance et l’intégrité des données.

Question centrale :

Comment gérer efficacement ces problèmes pour garantir la fiabilité et la disponibilité des systèmes ?

70%

des pannes de bases de données liées à des problèmes de concurrence

Étude DBTA, 2025

-45%

de deadlocks avec une bonne stratégie de verrouillage

Oracle Performance Study, 2026

Schéma des problèmes de concurrence en base de données

Diagramme des 4 types de problèmes de concurrence

1. Comprendre les problèmes de concurrence

1.1 Définition de la concurrence

La concurrence en base de données survient lorsqu’un ou plusieurs utilisateurs ou processus tentent d’accéder ou de modifier les mêmes données en même temps. Elle est particulièrement critique dans les systèmes transactionnels où les opérations doivent être exécutées de manière fiable et cohérente.

Schéma de la concurrence en base de données

1.2 Types de problèmes de concurrence

ProblèmeDescriptionConséquence
Lecture sale (Dirty Read)Un utilisateur lit des données modifiées mais non validéesDécision basée sur des données qui seront annulées
Lecture non répétable (Non-Repeatable Read)Une même requête retourne des résultats différentsIncohérence des analyses
Phantom Read (lecture fantôme)Apparition/disparition de lignes entre deux lecturesAgrégations faussées
Deadlock (blocage mutuel)Deux processus s’attendent mutuellementBlocage complet des transactions

Exemple de Deadlock

-- Transaction A
BEGIN;
UPDATE comptes SET solde = solde - 100 WHERE id = 1;
UPDATE comptes SET solde = solde + 100 WHERE id = 2;
COMMIT;

-- Transaction B (simultanée)
BEGIN;
UPDATE comptes SET solde = solde - 50 WHERE id = 2;
UPDATE comptes SET solde = solde + 50 WHERE id = 1;
COMMIT;
-- Résultat : chaque transaction attend le verrou de l'autre → DEADLOCK

Types de problèmes de concurrence

2. Approches pour gérer les problèmes de concurrence

Gestion de la concurrence - vue d'ensemble

2.1 Isolation des transactions

Le concept d’isolation garantit que les opérations d’une transaction n’affectent pas les autres transactions.

Niveau d’isolationDirty ReadNon-Repeatable ReadPhantom ReadPerformance
Read Uncommitted⚠️ Possible⚠️ Possible⚠️ Possible✅ Maximale
Read Committed (défaut PostgreSQL, SQL Server)✅ Impossible⚠️ Possible⚠️ Possible✅ Bonne
Repeatable Read (défaut MySQL InnoDB)✅ Impossible✅ Impossible⚠️ PossibleModérée
Serializable✅ Impossible✅ Impossible✅ ImpossibleRéduite

Définir le niveau d’isolation (PostgreSQL)

-- Niveau Read Committed (par défaut)
BEGIN;
SELECT * FROM produits WHERE id = 1;
COMMIT;

-- Niveau Serializable (pour les transactions critiques)
BEGIN ISOLATION LEVEL SERIALIZABLE;
SELECT * FROM produits WHERE id = 1;
UPDATE produits SET stock = stock - 1 WHERE id = 1;
COMMIT;

Niveaux d'isolation des transactions

2.2 Verrouillage (Locking)

Pessimiste

Verrouillage préventif (bloque les accès concurrents)

Optimiste

Vérification à la validation (permet les accès)

Verrouillage pessimiste (SQL Server)

BEGIN TRANSACTION;
-- Verrou exclusif sur la ligne
SELECT * FROM produits WITH (UPDLOCK) WHERE id = 1;
UPDATE produits SET stock = stock - 1 WHERE id = 1;
COMMIT;

Mécanismes de verrouillage

2.3 Gestion des Deadlocks

Bonnes pratiques anti-deadlock :

  • Accédez aux tables dans un ordre cohérent dans toutes les transactions
  • Réduisez la durée des transactions (le temps passé sous verrou)
  • Utilisez des index pour éviter les verrous au niveau table
  • Détectez et gérez les erreurs de deadlock (retry automatique)

Schéma d'un deadlock

2.4 Horodatage (Timestamping)

Contrôle de version optimiste (MongoDB)

// Lecture du document avec sa version
const doc = db.collection.find({ _id: 1 });
const version = doc.version;

// Modification
db.collection.updateOne(
  { _id: 1, version: version },
  { $set: { stock: 99 }, $inc: { version: 1 } }
);
// Si version a changé, la mise à jour échoue

Gestion par horodatage

2.5 Architecture de gestion des transactions distribuées

Cohérence dans les bases distribuées

3. Cas concrets de gestion

3.1 Système de réservation en ligne

Problème : Double réservation de la dernière chambre d’hôtel.
Solution : Verrouillage pessimiste avec MySQL InnoDB.

Réservation sécurisée

START TRANSACTION;
-- Verrou exclusif sur la ligne de la chambre
SELECT * FROM chambres WHERE id = 1 FOR UPDATE;

-- Vérification et réservation
UPDATE chambres SET disponible = FALSE WHERE id = 1 AND disponible = TRUE;

-- Insertion de la réservation
INSERT INTO reservations (chambre_id, client_id, date) VALUES (1, 123, NOW());

COMMIT;

3.2 Gestion des stocks (e-commerce)

Problème : Vente du même produit en stock limité à plusieurs clients.
Solution : Verrouillage optimiste avec Redis (Redlock).

3.3 Gestion documentaire collaborative

Problème : Conflits de version sur document partagé.
Solution : Algorithme de fusion CRDT (comme Google Docs).

4. Outils de surveillance et résolution

OutilFonctionnalités clésType
Database Performance Analyzer (SolarWinds)Surveillance des blocages, analyse des deadlocksPayant
pg_stat_activity (PostgreSQL)Visualisation des verrous actifs, requêtes bloquéesGratuit (intégré)
MySQL Performance SchemaMétriques de contention, wait eventsGratuit (intégré)
Apache KafkaGestion de l’ordre des messagesOpen source

PostgreSQL : identifier les verrous actifs

SELECT 
    blocked_locks.pid AS blocked_pid,
    blocked_activity.query AS blocked_query,
    blocking_locks.pid AS blocking_pid,
    blocking_activity.query AS blocking_query
FROM pg_locks blocked_locks
JOIN pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_locks blocking_locks ON blocking_locks.locktype = blocked_locks.locktype
    AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
    AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
    AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
    AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
    AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
    AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
    AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
    AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
    AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
    AND blocking_locks.pid != blocked_locks.pid
JOIN pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

5. Bonnes pratiques

1. Choisissez le bon niveau d’isolation

Read Committed pour la plupart des cas (bon compromis). Serializable uniquement pour les transactions critiques.

2. Minimisez la durée des transactions

Déplacez les opérations non critiques (logs, notifications) hors de la transaction.

3. Accédez aux ressources dans un ordre cohérent

Toujours accéder aux tables dans le même ordre (ex: table A puis B) pour éviter les deadlocks.

4. Utilisez des index adaptés

Les index permettent des verrous plus fins (ligne/range) plutôt que des verrous table.

5. Implémentez une logique de retry

Les deadlocks arrivent. Votre application doit être capable de réessayer automatiquement.

6. Comparatif des approches

ApprocheAvantagesInconvénientsIdéal pour
Verrouillage pessimisteTrès sûr, prévisibleRisque de deadlocks, moins scalableRéservations, transactions courtes
Verrouillage optimisteScalable, peu de deadlocksConflits possibles à la validationLectures fréquentes, rares modifications
TimestampingPas de verrouillage, idéal distribuéComplexité, coût de versioningSystèmes distribués, NoSQL
Isolation SerializableGarantie maximalePerformance réduite, rejeux fréquentsTransactions critiques (finance)

FAQ

Quelle est la différence entre un deadlock et un blocage (lock wait) ?

Un blocage (lock wait) est temporaire : une transaction attend qu'une autre libère un verrou, puis continue. Un deadlock est une situation où deux transactions s'attendent mutuellement indéfiniment. Les SGBD résolvent les deadlocks automatiquement en annulant l'une des transactions.

Comment éviter les deadlocks dans une application ?

Principales techniques : (1) accéder aux tables dans un ordre cohérent, (2) garder les transactions courtes, (3) utiliser des index pour éviter les verrous table, (4) implémenter des retry automatiques, (5) éviter les interactions utilisateur au sein d'une transaction.

Quel niveau d'isolation choisir par défaut ?

Read Committed est le meilleur compromis pour la plupart des applications. Il évite les lectures sales sans pénaliser trop la performance. Passez à Repeatable Read ou Serializable seulement si votre application en a besoin (ex: calculs financiers).

Les bases NoSQL gèrent-elles la concurrence ?

Oui, mais différemment. MongoDB utilise le verrouillage optimiste au niveau document. Cassandra propose des "lightweight transactions" (paxos) pour des cas limités. Redis a des commandes atomiques et des verrous distribués (Redlock). Le compromis est souvent entre cohérence forte et performance.

Comment détecter un deadlock sur PostgreSQL ?

PostgreSQL détecte automatiquement les deadlocks et annule la transaction la plus récente avec le message ERROR: deadlock detected. Vous pouvez consulter les logs avec log_lock_waits = on et surveiller pg_stat_activity pour les transactions bloquées.

Qu'est-ce que le 2PC (Two-Phase Commit) ?

Le Two-Phase Commit est un protocole qui garantit la cohérence des transactions distribuées sur plusieurs bases. Phase 1 : chaque base prépare la transaction (promet qu'elle pourra être validée). Phase 2 : toutes les bases valident (commit) ou annulent (rollback). Garantit l'atomicité, mais peut bloquer en cas de panne.

Faites parler vos données
Apprenez les méthodes et les outils pour extraire de la valeur stratégique : Data Science : Le guide complet des méthodes et outils.

Conclusion

La gestion des problèmes de concurrence d’accès à une base de données est cruciale pour garantir la fiabilité, la cohérence et la performance des systèmes informatiques modernes.

À retenir

  • 4 types de problèmes : Dirty Read, Non-Repeatable Read, Phantom Read, Deadlock
  • 4 niveaux d’isolation : Read Uncommitted, Read Committed, Repeatable Read, Serializable
  • 2 stratégies de verrouillage : pessimiste (bloque) vs optimiste (contrôle)
  • Outils de surveillance : pg_stat_activity, Performance Schema, DPA
  • Bonnes pratiques : transactions courtes, ordre d’accès cohérent, retry automatique

Pour aller plus loin : Découvrez notre guide complet sur la suppression en cascade pour comprendre la gestion des relations et des contraintes.