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 .