PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

aparente violação de isolamento de transação no postgresql


Sim e Não - como de costume, depende. A documentação diz estritamente que:

Em outras palavras, simplesmente SELECT difere de SELECT FOR UPDATE/DELETE/UPDATE.

Você pode criar um caso de teste simples para observar esse comportamento:

Sessão 1
test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> DELETE FROM test;
DELETE 10
test=>

Agora faça login em outra Sessão 2:
test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;

Após o último comando SELECT ... FOR UPDATE a sessão 1 "trava" e está esperando algo ......

De volta à sessão 1
test=> insert into test select * from generate_series(1,10);
INSERT 0 10
test=> commit;
COMMIT

E agora, quando você voltar para a sessão 2, verá isto:
test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;
 x
---
(0 rows)


test=> select * from test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)

Isto é - simples SELECT ainda não vê nenhuma alteração, enquanto SELECT ... FOR UPDATE vê que as linhas foram excluídas. Mas não vê novas linhas inseridas pela sessão 1



Na verdade, uma sequência que você está vendo é:
  • processo A inicia sua transação
  • processo A exclui tudo da tabela T
  • processo B inicia sua transação
  • o processo B tenta uma seleção para atualização em uma linha na tabela T
  • processo B "trava" e está esperando até que a sessão A faça um commit ou rollback
  • processo A repovoa a tabela T dos dados recebidos
  • processo A confirma sua transação
  • o processo B aparece vazio (0 linhas - após o commit da sessão A) e chama o rollback