Използвайте изрично заключване на ниво ред в подредени подзаявки във всички конкуриращи се заявките .
(SELECT
не се конкурира със заключванията при запис.)
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;
По този начин редовете се заключват в последователен ред, както е посочено в ръководството.
Ако приемем, че id_A
, id_B
никога не се актуализират, дори редки усложнения в ъгловия корпус, като подробно описаните в полето „Внимание“ в ръководството, не са възможни.
Докато не актуализирате ключовите колони, можете да използвате по-слабия режим на заключване FOR NO KEY UPDATE
. Изисква Postgres 9.3 или по-нова версия.
Другият (бавен и сигурно) опцията е да използвате ниво на изолация, което може да се сериализира за конкурентни транзакции. Ще трябва да се подготвите за неуспехи на сериализацията, в който случай трябва да опитате отново командата.