Używaj jawnego blokowania na poziomie wiersza w uporządkowanych podzapytaniach we wszystkich konkurencyjnych zapytaniach .
(SELECT
nie konkuruje z blokadami zapisu.)
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;
W ten sposób wiersze są blokowane w spójnej kolejności, zgodnie z zaleceniami w instrukcji.
Zakładając, że id_A
, id_B
nigdy nie są aktualizowane, nawet rzadkie komplikacje przypadków narożnych, takie jak wyszczególnione w polu „Uwaga” w instrukcji, nie są możliwe.
Jeśli nie aktualizujesz kolumn kluczy, możesz użyć słabszego trybu blokady FOR NO KEY UPDATE
. Wymaga Postgresa 9.3 lub nowszego.
Drugi (wolny i na pewno) jest opcja użycia serializowalnego poziomu izolacji dla transakcji konkurujących. Musiałbyś przygotować się na błędy serializacji, w którym to przypadku musisz ponowić polecenie.