Надеюсь, простой вопрос, но тот, для которого я не нашел подходящего ответа. Я уверенно информирован о том, что хранимые процедуры (пользовательские функции DB) в PostgreSQL (в частности, версия 9.0.4) по сути являются транзакционными, поскольку они вызываются с помощью инструкции SELECT, которая сама является транзакцией. Итак, как выбрать уровень изоляции хранимой процедуры? Я верю, что в других СУБД желаемый блок транзакций будет завернут в блок START TRANSACTION, для которого желаемый уровень изоляции является необязательным параметром.установить уровень изоляции для postgresql хранимых процедур
В качестве конкретного выдуманным, например, сказать, что я хочу сделать это:
CREATE FUNCTION add_new_row(rowtext TEXT)
RETURNS VOID AS
$$
BEGIN
INSERT INTO data_table VALUES (rowtext);
UPDATE row_counts_table SET count=count+1;
END;
$$
LANGUAGE plpgsql
SECURITY DEFINER;
И представьте себе, я хочу, чтобы убедиться, что эта функция всегда выполняется как сериализуемой сделки (да, да, PostgreSQL SERIALIZABLE ISN 'надлежащий сериализуемый, но это не главное). Я не хочу, чтобы он назывался
START TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT add_new_row('foo');
COMMIT;
Итак, как я могу вытащить необходимый уровень изоляции в функцию? Я считаю, что я не могу просто поставить уровень изоляции в BEGIN
заявлении в качестве the manual says
Важно не путать использование из BEGIN/END для группировки операторов в PL/PgSQL с аналогичным названием SQL команды для управления транзакциями. PL/pgSQL BEGIN/END предназначены только для группы ; они не запускают и не завершают транзакцию . Функции и инициируют процедуры всегда выполняются в рамках сделки, установленной внешней запроса - они не могут начать или совершить , что сделка, так как не было бы никакого контекста для их выполнения в
Наиболее очевидным. подход ко мне было бы использовать SET TRANSACTION
где-то в определении функции, например ,:
CREATE FUNCTION add_new_row(rowtext TEXT)
RETURNS VOID AS
$$
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
INSERT INTO data_table VALUES (rowtext);
UPDATE row_counts_table SET count=count+1;
END;
$$
LANGUAGE plpgsql
SECURITY DEFINER;
в то время как это было принято, не ясно, чем я могу рассчитывать на эту работу. documentation для SET TRANSACTION
говорит
Если SET TRANSACTION выполняется без предшествующего START TRANSACTION или начать, появится не иметь никакого эффекта, так как сделки будет немедленно положить конец.
Который оставляет меня озадачило, так как если я называю уединенную SELECT add_new_row('foo');
заявление, которое я бы ожидать (если я не отключили AutoCommit) ВЫБОР быть запущен как сделки однострочного с уровнем изоляции сеанса по умолчанию.
manual также говорит: Уровень изоляции
сделка не может быть изменен после первого запроса или данных модификации заявления (ВЫБОР, INSERT, DELETE, UPDATE, FETCH или копия) совершена транзакция .
Так что же происходит, если функция вызывается из транзакции с более низким уровнем изоляции, например,:.
START TRANSACTION ISOLATION LEVEL READ COMMITTED;
UPDATE row_counts_table SET count=0;
SELECT add_new_row('foo');
COMMIT;
Для бонусного вопроса: имеет ли язык функции никакой разницы? Можно ли установить уровень изоляции по-разному в PL/pgSQL, чем в обычном SQL?
Я поклонник стандартов и задокументированных лучших практик, поэтому любые достойные ссылки будут оценены.
Что произошло, когда вы пытались использовать 'SET TRANSACTION' внутри функции? –
@a_horse_with_no_name: Как я уже упоминал, я считаю, что «SET TRANSACTION» - это то, что мне нужно, и функции с ним принимаются, но иногда это не означает много (некоторые параметры иногда проглатываются), поэтому я ищу документированный подход, а не нечто, что, похоже, работает. – beldaz
Postgres редко проглатывает то, что вы ему рассказываете, - и когда это произойдет, я ожидаю, что он выдает предупреждение. –