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

Bloqueio e transação no postgres que deve bloquear uma consulta


O comportamento que você descreve é ​​normal e esperado em qualquer banco de dados relacional transacional.

Se o PostgreSQL mostrou o valor edited para o primeiro SELECT seria errado fazê-lo - isso é chamado de "leitura suja" e é uma má notícia em bancos de dados.

PostgreSQL teria permissão para esperar no SELECT até você confirmar ou reverter, mas não é exigido pelo padrão SQL, você não disse que quer esperar e não precisa esperar por nenhum motivo técnico, então ele retorna os dados que você pediu para imediatamente. Afinal, até que seja confirmado, essa update apenas meio que existe - ainda pode ou não acontecer.

Se o PostgreSQL sempre esperasse aqui, você chegaria rapidamente a uma situação em que apenas uma conexão poderia estar fazendo alguma coisa com o banco de dados por vez. Não é bonito para o desempenho e totalmente desnecessário na grande maioria das vezes.

Se você quiser esperar por um UPDATE simultâneo (ou DELETE ), você usaria SELECT ... FOR SHARE . (Mas esteja ciente de que isso não funcionará para INSERT ).

Detalhes:

SELECT sem um FOR UPDATE ou FOR SHARE cláusula não aceita nenhum bloqueio de nível de linha. Portanto, ele vê a linha confirmada atual e não é afetado por nenhuma transação em andamento que possa estar modificando essa linha. Os conceitos são explicados na seção MVCC dos documentos . A ideia geral é que o PostgreSQL é copy-on-write, com versionamento que permite retornar a cópia correta com base no que a transação ou instrução pode "ver" no momento em que foi iniciada - o que o PostgreSQL chama de "instantâneo".

No padrão READ COMMITTED os instantâneos de isolamento são obtidos no nível da instrução, portanto, se você SELECT uma linha, COMMIT uma alteração de outra transação e SELECT novamente, você verá valores diferentes mesmo em uma transação. Você pode usar SNAPSHOT isolamento se você não quiser ver as alterações confirmadas após o início da transação, ou SERIALIZABLE isolamento para adicionar mais proteção contra certos tipos de interdependências de transações.

Consulte o capítulo de isolamento de transações na documentação .

Se você quiser um SELECT para aguardar as transações em andamento confirmarem ou reverterem as alterações nas linhas selecionadas, você deve usar SELECT ... FOR SHARE . Isso bloqueará o bloqueio obtido por um UPDATE ou DELETE até que a transação que pegou o bloqueio seja revertida ou confirmada.

INSERT é diferente, porém - as tuplas simplesmente não existem para outras transações até o commit. A única maneira de esperar por INSERT simultâneos s é pegar um EXCLUSIVE bloqueio no nível da tabela, para que você saiba que ninguém mais está alterando a tabela enquanto você a lê. Normalmente, a necessidade de fazer isso significa que você tem um problema de design no aplicativo - seu aplicativo não deve se importar se houver insert não confirmados ainda está em vôo.

Veja o capítulo de bloqueio explícito da documentação .