Ayúdame a comprender el caso de uso subyacente SELECT ... FOR UPDATE.
Pregunta 1 : ¿Es el siguiente un buen ejemplo de cuándo SELECT ... FOR UPDATEdebe usarse?
Dado:
- habitaciones [id]
- etiquetas [id, nombre]
- room_tags [room_id, tag_id]
- room_id y tag_id son claves externas
La aplicación quiere enumerar todas las habitaciones y sus etiquetas, pero necesita diferenciar las habitaciones sin etiquetas de las habitaciones que se han eliminado. Si SELECT ... FOR UPDATE no se usa, lo que podría suceder es:
- Inicialmente:
- habitaciones contiene
[id = 1] - etiquetas contiene
[id = 1, name = 'cats'] - room_tags contiene
[room_id = 1, tag_id = 1]
- habitaciones contiene
- Hilo 1:
SELECT id FROM rooms;returns [id = 1]
- Hilo 2:
DELETE FROM room_tags WHERE room_id = 1; - Hilo 2:
DELETE FROM rooms WHERE id = 1; - Hilo 2: [confirma la transacción]
- Hilo 1:
SELECT tags.name FROM room_tags, tags WHERE room_tags.tag_id = 1 AND tags.id = room_tags.tag_id;- devuelve una lista vacía
Ahora el hilo 1 piensa que la habitación 1 no tiene etiquetas, pero en realidad la habitación se ha eliminado. Para resolver este problema, el hilo 1 debería SELECT id FROM rooms FOR UPDATE, evitando así que el hilo 2 se elimine roomshasta que el hilo 1 esté terminado. ¿Es eso correcto?
Pregunta 2 : ¿Cuándo se debe utilizar el SERIALIZABLEaislamiento de transacciones frente a READ_COMMITTEDcon SELECT ... FOR UPDATE?
Se espera que las respuestas sean portátiles (no específicas de la base de datos). Si eso no es posible, explique por qué.

REPEATABLE_READeREAD_COMMITTEDincluso las opciones portátiles? Los únicos resultados que obtengo son para el servidor MSSQLREAD COMMITTEDmodo no define si realmente verá o no los registros comprometidos por otra transacción: solo se asegura de que nunca verá registros no confirmados.select ... for updateonroomstodavía permitirároom_tagsque se eliminen porque son tablas separadas. ¿Quería preguntar si lafor updatecláusula evitará las eliminacionesrooms?Respuestas:
La única forma portátil de lograr la coherencia entre las habitaciones y las etiquetas y asegurarse de que las habitaciones nunca se devuelvan después de haber sido eliminadas es bloquearlas con
SELECT FOR UPDATE.Sin embargo, en algunos sistemas el bloqueo es un efecto secundario del control de simultaneidad y se obtienen los mismos resultados sin especificar
FOR UPDATEexplícitamente.Esto depende del control de concurrencia que esté usando su sistema de base de datos.
MyISAMinMySQL(y varios otros sistemas antiguos) bloquea toda la tabla durante una consulta.En
SQL Server, lasSELECTconsultas colocan bloqueos compartidos en los registros / páginas / tablas que han examinado, mientras que lasDMLconsultas colocan bloqueos de actualización (que luego son promovidos a exclusivos o degradados a bloqueos compartidos). Los bloqueos exclusivos son incompatibles con los bloqueos compartidos, por lo queSELECTo laDELETEconsulta se bloqueará hasta que se confirme otra sesión.En las bases de datos cuyo uso
MVCC(comoOracle,PostgreSQL,MySQLconInnoDB), unaDMLconsulta crea una copia del registro (en uno u otro sentido) y, en general los lectores no bloquean escritores y viceversa. Para estas bases de datos,SELECT FOR UPDATEsería útil: bloquearíaSELECTo laDELETEconsulta hasta que se confirme otra sesión, al igual que loSQL Serverhace.Generalmente,
REPEATABLE READno prohíbe las filas fantasma (filas que aparecieron o desaparecieron en otra transacción, en lugar de ser modificadas)En
OracleyPostgreSQLversiones anteriores ,REPEATABLE READes en realidad un sinónimo deSERIALIZABLE. Básicamente, esto significa que la transacción no ve los cambios realizados después de que ha comenzado. Entonces, en esta configuración, la últimaThread 1consulta devolverá la habitación como si nunca se hubiera eliminado (que puede ser o no lo que deseaba). Si no desea mostrar las habitaciones después de que se hayan eliminado, debe bloquear las filas conSELECT FOR UPDATEEn
InnoDB,REPEATABLE READySERIALIZABLEson cosas diferentes: los lectores enSERIALIZABLEmodo establecen bloqueos de siguiente clave en los registros que evalúan, evitando de manera efectiva la concurrenciaDMLen ellos. Por lo tanto, no necesita unSELECT FOR UPDATEmodo serializable, pero sí los necesita enREPEATABLE READoREAD COMMITED.Tenga en cuenta que el estándar sobre modos de aislamiento prescribe que no ve ciertas peculiaridades en sus consultas, pero no define cómo (con bloqueo o con
MVCCo de otro modo).Cuando digo "no es necesario
SELECT FOR UPDATE", debería haber agregado "debido a los efectos secundarios de la implementación de cierto motor de base de datos".fuente
SERIALIZABLEdebería usarse versusREAD_COMMITTEDconSELECT ... FOR UPDATE. ¿Puede actualizar su respuesta para reflejar esta pregunta actualizada?SELECT FOR UPDATEen modo serializable", conInnoDB. Con los otrosMVCCsistemas, los dos son sinónimos y los necesitaSELECT FOR UPDATE.This depends on the concurrency control your database system is using: Creo que te estás partiendo los pelos. Todos los casos que enumera a continuación dicen que la sala no se eliminaSELECThasta el final de la transacción. Entonces, ¿no debería la respuesta simplementeYescon las referencias de apoyo a continuación?Respuestas cortas:
Q1: Sí.
P2: No importa cuál uses.
Respuesta larga:
A
select ... for update(como implica) seleccionará ciertas filas pero también las bloqueará como si ya hubieran sido actualizadas por la transacción actual (o como si la actualización de identidad se hubiera realizado). Esto le permite actualizarlos nuevamente en la transacción actual y luego confirmar, sin que otra transacción pueda modificar estas filas de ninguna manera.Otra forma de verlo, es como si las siguientes dos declaraciones se ejecutaran de forma atómica:
Dado que las filas afectadas por
my_conditionestán bloqueadas, ninguna otra transacción puede modificarlas de ninguna manera y, por lo tanto, el nivel de aislamiento de la transacción no hace ninguna diferencia aquí.Tenga en cuenta también que el nivel de aislamiento de la transacción es independiente del bloqueo: establecer un nivel de aislamiento diferente no le permite evitar el bloqueo y actualizar filas en una transacción diferente que están bloqueadas por su transacción.
Lo que los niveles de aislamiento de transacciones garantizan (en diferentes niveles) es la coherencia de los datos mientras las transacciones están en curso.
fuente
What transaction isolation levels do guarantee [...] is the consistency of data once transactions are completed.implica incorrectamente que los niveles de aislamiento no afectan lo que sucede durante una transacción. Recomiendo revisar esta sección y proporcionar más detalles sobre cómo afectan lo que ve (o no ve) durante una transacción.