El comportamiento que describe es normal y esperado en cualquier base de datos relacional transaccional.
Si PostgreSQL le mostró el valor edited
para el primer SELECT
sería incorrecto hacerlo, eso se llama "lectura sucia" y es una mala noticia en las bases de datos.
A PostgreSQL se le permitiría esperar en SELECT
hasta que se comprometiera o retrocediera, pero el estándar SQL no lo requiere, no le ha dicho que desea esperar, y no tiene que esperar por ningún motivo técnico, por lo que devuelve los datos que solicitó para inmediatamente. Después de todo, hasta que se confirme, esa update
solo existe una especie de - todavía podría suceder o no.
Si PostgreSQL siempre esperara aquí, entonces rápidamente llegaría a una situación en la que solo una conexión podría estar haciendo algo con la base de datos a la vez. No es bonito para el rendimiento y es totalmente innecesario la gran mayoría de las veces.
Si desea esperar una UPDATE
concurrente (o DELETE
), usaría SELECT ... FOR SHARE
. (Pero tenga en cuenta que esto no funcionará para INSERT
).
Detalles:
SELECT
sin FOR UPDATE
o FOR SHARE
cláusula no toma ningún bloqueo de nivel de fila. Por lo tanto, ve la fila confirmada actual y no se ve afectada por ninguna transacción en curso que pueda estar modificando esa fila. Los conceptos se explican en la sección MVCC de la documentación
. La idea general es que PostgreSQL es copia sobre escritura, con control de versiones que le permite devolver la copia correcta en función de lo que la transacción o declaración pudo "ver" en el momento en que comenzó, lo que PostgreSQL llama una "instantánea".
En el valor predeterminado READ COMMITTED
las instantáneas de aislamiento se toman a nivel de declaración, por lo que si SELECT
una fila, COMMIT
un cambio de otra transacción, y SELECT
de nuevo, verá diferentes valores incluso dentro de una transacción. Puedes usar SNAPSHOT
aislamiento si no desea ver los cambios confirmados después de que comience la transacción, o SERIALIZABLE
aislamiento para agregar más protección contra ciertos tipos de interdependencias de transacciones.
Consulte el capítulo de aislamiento de transacciones en la documentación .
Si quieres un SELECT
para esperar a que las transacciones en curso confirmen o reviertan los cambios en las filas que se están seleccionando, debe usar SELECT ... FOR SHARE
. Esto bloqueará el bloqueo tomado por un UPDATE
o DELETE
hasta que la transacción que tomó el bloqueo retroceda o se confirme.
INSERT
Sin embargo, es diferente:las tuplas simplemente no existen para otras transacciones hasta que se confirmen. La única forma de esperar INSERT
concurrentes s es tomar una EXCLUSIVE
Bloqueo a nivel de mesa, para que sepa que nadie más está cambiando la mesa mientras la lee. Por lo general, la necesidad de hacer eso significa que tiene un problema de diseño en la aplicación; sin embargo, su aplicación no debería importar si hay insert
no confirmados s todavía en vuelo.
Consulte el capítulo de bloqueo explícito de la documentación .