У меня проблема:
У меня есть функция PostgreSQL, которая выполняет FOR цикл по table_a записям и вставляет в table_b данные из обеих таблиц, и все записи связаны одним и тем же номером процесса.
Пример:
DECLARE
......
BEGIN
FOR rec in
(select * from table_a where *some_condition*)
LOOP
some_value := (select value from table_b where some_condition_2);
insert into table_b (some_field, process) VALUES (some_value + rec.other_value, some_process);
END LOOP
COMMIT;
END;
Если я вызову эту функцию одновременно в двух сеансах, ожидаемый результат в table_a должен быть:
(process 1) record 1
(process 1) record 2
(process 1) record 3
(process 1) record 4
(process 1) record 5
(process 2) record 6
(process 2) record 7
(process 2) record 8
(process 2) record 9
(process 2) record 10
Потому что я предполагаю, что когда я вызываю функцию, все вставки должны выполняться подряд без перерыва.
Но иногда они выполняются таким образом:
(process 1) record 1
(process 1) record 2
(process 1) record 3
(process 2) record 4 (*)
(process 1) record 5
(process 2) record 6 (*)
(process 1) record 7
(process 2) record 8
(process 2) record 9
(process 2) record 10
И значение some_field в table_a неверно.
Почему это происходит?
Ничто не препятствует одновременному запуску функции в нескольких сеансах и одновременному выбору и вставке данных.
Чтобы убедиться, что никакие два вызова функции не могут выполняться одновременно, лучше всего использовать рекомендательную блокировку:
CREATE FUNCTION ... AS
$$BEGIN
PERFORM pg_advisory_lock(42);
/* processing */
PERFORM pg_advisory_unlock(42);
END;$$;
Ключ 42 - это число по вашему выбору.