Utilizza il blocco a livello di riga esplicito nelle sottoquery ordinate in tutte le query concorrenti .
(SELECT
non compete con i blocchi di scrittura.)
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;
In questo modo, le righe vengono bloccate in un ordine coerente come consigliato nel manuale.
Supponendo che id_A
, id_B
non sono mai aggiornati, anche rare complicazioni di casi angolari come dettagliate nella casella "Attenzione" nel manuale non sono possibili.
Pur non aggiornando le colonne chiave, puoi utilizzare la modalità di blocco più debole FOR NO KEY UPDATE
. Richiede Postgres 9.3 o successivo.
L'altro (lento e certo) l'opzione consiste nell'utilizzare il livello di isolamento serializzabile per le transazioni concorrenti. Dovresti prepararti per errori di serializzazione, nel qual caso devi riprovare il comando.