Sommaire
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

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.

1.2 Types de problèmes de concurrence
| Problème | Description | Conséquence |
|---|---|---|
| Lecture sale (Dirty Read) | Un utilisateur lit des données modifiées mais non validées | Dé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érents | Incohérence des analyses |
| Phantom Read (lecture fantôme) | Apparition/disparition de lignes entre deux lectures | Agrégations faussées |
| Deadlock (blocage mutuel) | Deux processus s’attendent mutuellement | Blocage 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
2. Approches pour gérer les problèmes de concurrence

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’isolation | Dirty Read | Non-Repeatable Read | Phantom Read | Performance |
|---|---|---|---|---|
| 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 | ⚠️ Possible | Modérée |
| Serializable | ✅ Impossible | ✅ Impossible | ✅ Impossible | Ré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;
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;
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)

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
2.5 Architecture de gestion des transactions 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
| Outil | Fonctionnalités clés | Type |
|---|---|---|
| Database Performance Analyzer (SolarWinds) | Surveillance des blocages, analyse des deadlocks | Payant |
| pg_stat_activity (PostgreSQL) | Visualisation des verrous actifs, requêtes bloquées | Gratuit (intégré) |
| MySQL Performance Schema | Métriques de contention, wait events | Gratuit (intégré) |
| Apache Kafka | Gestion de l’ordre des messages | Open 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
| Approche | Avantages | Inconvénients | Idéal pour |
|---|---|---|---|
| Verrouillage pessimiste | Très sûr, prévisible | Risque de deadlocks, moins scalable | Réservations, transactions courtes |
| Verrouillage optimiste | Scalable, peu de deadlocks | Conflits possibles à la validation | Lectures fréquentes, rares modifications |
| Timestamping | Pas de verrouillage, idéal distribué | Complexité, coût de versioning | Systèmes distribués, NoSQL |
| Isolation Serializable | Garantie maximale | Performance réduite, rejeux fréquents | Transactions 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.