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 .