Transações dentro de uma transação

18

Qual comportamento o PostgreSQL mostraria se, por exemplo, o script abaixo fosse chamado

BEGIN;
SELECT * FROM foo;
INSERT INTO foo(name) VALUES ('bar');
BEGIN; <- The point of interest
END;

O PostgreSQL descartaria o segundo BEGINou seria decidido implicitamente um commit e executaria o BEGIN ENDbloco no final como uma transação separada?

Alex
fonte

Respostas:

13

O que você precisa é de uma "transação autônoma" (um recurso fornecido pela oracle). Neste ponto, isso ainda não é possível no PostgreSQL. No entanto, você pode usar o SAVEPOINT s:

BEGIN;
INSERT ...
SAVEPOINT a;
some error;
ROLLBACK TO SAVEPOINT a;
COMMIT;

Não é inteiramente uma transação autônoma - mas permite que você obtenha "todas as transações" corretamente. Você pode usá-lo para alcançar o que espera de transações autônomas.

Caso contrário, não há outra solução razoável neste momento.

Hans-Jürgen Schönig
fonte
13

Você pode tentar você mesmo:

AVISO: já existe uma transação em andamento

Não inicia nenhuma (sub) transação nova, pois as transações aninhadas não são implementadas no PostgreSQL. (Você pode fazer alguma mágica em uma pl/pgsqlfunção, por exemplo, que imita esse comportamento.)

Com o PostgreSQL 11, era possível pensar que os novos procedimentos reais armazenados e sua capacidade de lidar com transações tornariam possíveis transações aninhadas. No entanto, de acordo com a documentação , este não é o caso:

Nos procedimentos invocados pelo CALLcomando, bem como nos blocos de códigos anônimos ( DOcomando), é possível finalizar transações usando os comandos COMMITe ROLLBACK. Uma nova transação é iniciada automaticamente após o término de uma transação usando esses comandos, portanto, não há um comando START TRANSACTION separado.

dezso
fonte
9

O PostgreSQL não suporta sub-transações, mas o SAVEPOINTrecurso pode efetivamente atender sua necessidade. Citando a documentação da camada de acesso Avançado ao PG via promessas de Vitaly Tomilov no GitHub:

O PostgreSQL não possui suporte adequado para transações aninhadas, apenas suporta reversões parciais por meio de pontos de salvamento nas transações. A diferença entre as duas técnicas é enorme, como explicado mais adiante.

O suporte adequado para transações aninhadas significa que o resultado de uma sub-transação bem-sucedida não é revertido quando sua transação pai é revertida. Porém, com os pontos de salvamento do PostgreSQL, se você reverter a transação de nível superior, o resultado de todos os pontos de salvamento internos também será revertido.

Os pontos de salvamento podem ser usados ​​para reversões parciais para um ponto anterior dentro de uma transação ativa. Por exemplo, para estabelecer um ponto de salvamento e depois desfazer os efeitos de todos os comandos executados após o estabelecimento:

BEGIN;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (2);
    ROLLBACK TO SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (3);
COMMIT;

A transação acima irá inserir os valores 1 e 3, mas não 2. Consulte a SAVEPOINTdocumentação para obter mais informações.

Amir Ali Akbari
fonte
0

Para o Postgresql 9.5 ou mais recente, você pode usar trabalhadores de segundo plano dinâmicos fornecidos pela extensão pg_background. Cria transação autônoma. Por favor, consulte a página do github da extensão. A solução é melhor que o db_link. Existe um guia completo sobre suporte a transações autônomas no PostgreSQL

shcherbak
fonte