У меня проблема:
У меня есть функция 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 - это число по вашему выбору.