Interblocage (deadlock)
Qu’est-ce qu’un interblocage (deadlock) dans PostgreSQL et comment l’éviter ?
Un interblocage se produit lorsque deux transactions attendent chacune un verrou détenu par l’autre. PostgreSQL le détecte et annule l’une d’elles ; prendre les verrous dans un ordre cohérent permet de l’éviter.
Un interblocage est un cycle d’attentes de verrous : la transaction A détient un verrou dont B a besoin, tandis que B détient un verrou dont A a besoin, si bien qu’aucune ne peut continuer. PostgreSQL détecte automatiquement ces cycles et les résout en annulant l’une des transactions, qui reçoit une erreur deadlock detected.
La vérification ne s’exécute pas à chaque attente de verrou : une session attend d’abord deadlock_timeout (une seconde par défaut) avant de rechercher un cycle. La meilleure défense consiste à verrouiller les mêmes objets dans le même ordre dans chaque transaction, par exemple en verrouillant les lignes triées par clé primaire, et à garder des transactions courtes. Le code qui peut encore rencontrer un interblocage doit relancer la transaction annulée.
Exemple
L’exemple verrouille en une seule instruction, triées par id, les deux lignes qu’il s’apprête à modifier, avant de les mettre à jour. Lorsque toutes les transactions qui touchent ces lignes font de même, elles attendent leur tour au lieu de s’interbloquer.
CREATE TABLE ledger (id int PRIMARY KEY, balance int);
INSERT INTO ledger VALUES (1, 100), (2, 100);
SHOW deadlock_timeout;
BEGIN;
SELECT id FROM ledger WHERE id IN (1, 2) ORDER BY id FOR UPDATE;
UPDATE ledger SET balance = balance - 10 WHERE id = 1;
UPDATE ledger SET balance = balance + 10 WHERE id = 2;
COMMIT;Du SQL simple pour PostgreSQL 16 ou 17 standard, sans aucune extension. Exécutez-le dans une base de données vide que vous pouvez jeter ensuite.
Références
Documentation officielle de PostgreSQL (en anglais).