sql >> Base de Datos >  >> RDS >> PostgreSQL

Bloqueo y transacción en postgres que debería bloquear una consulta

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 .