Afortunadamente una pregunta simple, pero para la que no he encontrado una respuesta decente. Estoy informado de manera confiable que los procedimientos almacenados (funciones de base de datos definidas por el usuario) en PostgreSQL (específicamente, la versión 9.0.4) son inherentemente transaccionales, en la medida en que son llamados a través de una instrucción SELECT que a su vez es una transacción. Entonces, ¿cómo se elige el nivel de aislamiento del procedimiento almacenado? Creo en otros DBMS que el bloque transaccional deseado estaría envuelto en un bloque START TRANSACTION para el cual el nivel de aislamiento deseado es un parámetro opcional.establece el nivel de aislamiento para los procedimientos almacenados de postgresql
Como ejemplo maquillada específica, dicen que yo quiero hacer esto:
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;
E imagina que quiero para asegurarse de que esta función siempre se realiza como una transacción serializable (sí, sí, PostgreSQL ISN SERIALIZABLE no es serializable, pero ese no es el punto). No deseo requerir que se llame como
START TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT add_new_row('foo');
COMMIT;
Entonces, ¿cómo presiono el nivel de aislamiento requerido hacia abajo en la función? Creo que no puedo acaba de poner el nivel de aislamiento en la declaración BEGIN
, como the manual says
Es importante no confundir el uso de BEGIN/END para agrupar declaraciones en PL/pgSQL con el nombre similar SQL comandos para control de transacciones PL/pgSQL's BEGIN/END son solo para la agrupación ; no comienzan ni finalizan una transacción . Funciones y desencadenar procedimientos se ejecutan siempre dentro una transacción establecida por una consulta externa - no pueden iniciar o cometen esa transacción, ya que no habría ningún contexto para que se ejecuten en
La más obvia. enfoque para mí sería utilizar SET TRANSACTION
algún lugar de la definición de la función, por ejemplo ,:
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;
Si bien esto sería aceptado, no está claro lo que puedo confiar en que esto funcione. El documentation para SET TRANSACTION
dice
Si SET operación se ejecuta sin un comienzo o transacción antes de empezar, que se parecen tener ningún efecto, ya que la transacción terminará inmediatamente.
Lo que me deja perplejo, ya que si llamo una declaración solitaria SELECT add_new_row('foo');
Yo esperaría que (siempre que no se ha desactivado confirmación automática) SELECT que se ejecuta como una transacción de una sola línea con el nivel de aislamiento predeterminado sesión.
El manual también dice: nivel de aislamiento
La transacción no puede ser cambiado después de la primera consulta o declaración de modificación de datos (SELECT, INSERT, DELETE, UPDATE, FETCH o COPIA) de se ha ejecutado una transacción .
Entonces, ¿qué sucede si la función se llama desde dentro de una transacción con un nivel de aislamiento inferior, por ejemplo,:.
START TRANSACTION ISOLATION LEVEL READ COMMITTED;
UPDATE row_counts_table SET count=0;
SELECT add_new_row('foo');
COMMIT;
Para una pregunta extra: ¿el lenguaje de la función alguna diferencia? ¿Se establecería el nivel de aislamiento de forma diferente en PL/pgSQL que en SQL simple?
Soy un fanático de los estándares y las mejores prácticas documentadas, por lo que cualquier referencia decente sería apreciada.
¿Qué pasó cuando trataste de usar 'SET TRANSACTION' dentro de la función? –
@a_horse_with_no_name: Como mencioné, me imagino que 'SET TRANSACTION' es lo que necesito, y las funciones con él son aceptadas, pero a veces eso no significa mucho (algunas opciones simplemente se tragan a veces), así que estoy buscando un enfoque documentado en lugar de algo que simplemente parece funcionar. – beldaz
Postgres rara vez se traga lo que le dices que haga, y cuando lo haga, esperaría que emita una advertencia. –