Utiliser un verrouillage explicite au niveau de la ligne dans les sous-requêtes ordonnées dans toutes les requêtes concurrentes .
(SELECT
n'entre pas en concurrence avec les verrous en écriture.)
DELETE
DELETE FROM table_name t
USING (
SELECT id_A, id_B
FROM table_name
WHERE id_A = ANY(array_of_id_A)
AND id_B = ANY(array_of_id_B)
ORDER BY id_A, id_B
FOR UPDATE
) del
WHERE t.id_A = del.id_A
AND t.id_B = del.id_B;
UPDATE
UPDATE table_name t
SET val_1 = 'some value'
, val_2 = 'some value'
FROM (
SELECT id_A, id_B
FROM table_name
WHERE id_A = ANY(array_of_id_A)
AND id_B = ANY(array_of_id_B)
ORDER BY id_A, id_B
FOR NO KEY UPDATE -- Postgres 9.3+
-- FOR UPDATE -- for older versions or updates on key columns
) upd
WHERE t.id_A = upd.id_A
AND t.id_B = upd.id_B;
De cette façon, les lignes sont verrouillées dans un ordre cohérent, comme indiqué dans le manuel.
En supposant que id_A
, id_B
ne sont jamais mis à jour, même les rares complications de cas d'angle comme celles détaillées dans la case "Attention" du manuel ne sont pas possibles.
Sans mettre à jour les colonnes de clé, vous pouvez utiliser le mode de verrouillage plus faible FOR NO KEY UPDATE
. Nécessite Postgres 9.3 ou version ultérieure.
L'autre (lent et bien sûr) consiste à utiliser le niveau d'isolement sérialisable pour les transactions concurrentes. Vous devrez vous préparer aux échecs de sérialisation, auquel cas vous devrez réessayer la commande.