Diferencia entre "lectura comprometida" y "lectura repetible"

245

Creo que los niveles de aislamiento anteriores son muy parecidos. ¿Podría alguien describir con algunos buenos ejemplos cuál es la principal diferencia?

Delantero
fuente
3
Debe ampliar la pregunta y agregar etiquetas para el "nivel de aislamiento" al que se refiere (Java, etc.). "nivel de aislamiento" es un término algo ambiguo, y obviamente está pidiendo una respuesta para un entorno específico.
jesup

Respuestas:

564

Leer confirmado es un nivel de aislamiento que garantiza que cualquier lectura de datos se confirmó en el momento en que se lee. Simplemente restringe al lector de ver cualquier lectura intermedia, no comprometida, 'sucia'. No promete nada que si la transacción vuelve a emitir la lectura, encontrará los mismos datos, los datos son libres de cambiar después de ser leídos.

La lectura repetible es un nivel de aislamiento más alto, que además de las garantías del nivel comprometido de lectura, también garantiza que cualquier lectura de datos no puede cambiar , si la transacción lee los mismos datos nuevamente, encontrará los datos leídos previamente en su lugar, sin cambios. y disponible para leer.

El siguiente nivel de aislamiento, serializable, ofrece una garantía aún más sólida: además de todas las garantías de lectura repetibles, también garantiza que no se puedan ver nuevos datos en una lectura posterior.

Digamos que tiene una tabla T con una columna C con una fila, digamos que tiene el valor '1'. Y considere que tiene una tarea simple como la siguiente:

BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;

Esa es una tarea simple que emite dos lecturas de la tabla T, con un retraso de 1 minuto entre ellas.

  • bajo LEER COMPROMETIDO, el segundo SELECCIONAR puede devolver cualquier dato. Una transacción concurrente puede actualizar el registro, eliminarlo e insertar nuevos registros. La segunda selección siempre verá los nuevos datos.
  • bajo REPEATABLE READ, el segundo SELECT está garantizado para mostrar al menos las filas que se devolvieron del primer SELECT sin cambios . Se pueden agregar nuevas filas por una transacción concurrente en ese minuto, pero las filas existentes no se pueden eliminar ni cambiar.
  • bajo lecturas SERIALIZABLES se garantiza que la segunda selección vea exactamente las mismas filas que la primera. Ninguna fila puede cambiar, ni eliminarse, ni una nueva fila puede insertar nuevas filas.

Si sigue la lógica anterior, puede darse cuenta rápidamente de que las transacciones SERIALIZABLES, si bien pueden facilitarle la vida, siempre bloquean por completo todas las operaciones concurrentes posibles, ya que requieren que nadie pueda modificar, eliminar ni insertar ninguna fila. El nivel de aislamiento de transacción predeterminado del System.Transactionsámbito .Net es serializable, y esto generalmente explica el rendimiento abismal que resulta.

Y finalmente, también está el nivel de aislamiento SNAPSHOT. El nivel de aislamiento SNAPSHOT ofrece las mismas garantías que serializable, pero no requiere que ninguna transacción concurrente pueda modificar los datos. En cambio, obliga a cada lector a ver su propia versión del mundo (es su propia "instantánea"). Esto hace que sea muy fácil programar y muy escalable, ya que no bloquea las actualizaciones simultáneas. Sin embargo, ese beneficio tiene un precio: consumo adicional de recursos del servidor.

Lecturas suplementarias:

Remus Rusanu
fuente
24
Creo que hay un error anterior para REPEATABLE READ: Dices que las filas existentes no se pueden eliminar ni cambiar, pero creo que se pueden eliminar o cambiar porque la lectura repetible simplemente lee una "instantánea", no los datos reales. De los documentos dev.mysql.com/doc/refman/5.0/en/… : "Todas las lecturas consistentes dentro de la misma transacción leen la instantánea establecida por la primera lectura".
Derek Litz
2
@Derek Litz ¿Estoy en lo cierto al decir: los datos PUEDEN / PUEDEN cambiarse de un tercero, mientras se realiza la transacción, pero las lecturas seguirán viendo los datos originales 'antiguos' como si el cambio no hubiera tomado lugar (la instantánea).
Programador
55
@Tallos de maiz. Sí, las lecturas fantasmas pueden ocurrir por eliminaciones (o inserciones). Sí, las lecturas fantasmas pueden ocurrir en el aislamiento de lectura repetible (solo de inserciones). No, las lecturas fantasmas de las eliminaciones no pueden ocurrir en el aislamiento de lectura repetible. Pruébalo. Lo que digo no está en contradicción con la documentación que ha citado.
AndyBrown
44
@Cornstalks NP. ¡Solo lo mencioné en absoluto porque no estaba 100% seguro de mí mismo y tuve que profundizar para asegurarme de quién tenía razón! Y no quería que los futuros lectores se engañaran. Mantener los comentarios, probablemente lo mejor para mantener como se sugiere. ¡Estoy seguro de que cualquier otra persona interesada en ese nivel de detalle será lo suficientemente particular como para leer todos los comentarios!
AndyBrown
12
Gracias por no eliminar tus comentarios. La discusión ayuda a conectar más puntos.
Josh
68

Lectura repetible

El estado de la base de datos se mantiene desde el inicio de la transacción. Si recupera un valor en la sesión1, luego actualice ese valor en la sesión2, recuperarlo nuevamente en la sesión1 arrojará los mismos resultados. Las lecturas son repetibles.

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

session1> SELECT firstname FROM names WHERE id = 7;
Aaron

Leer comprometido

Dentro del contexto de una transacción, siempre recuperará el valor comprometido más reciente. Si recupera un valor en la sesión1, actualícelo en la sesión2, luego recupérelo en la sesión1 nuevamente, obtendrá el valor modificado en la sesión2. Lee la última fila comprometida.

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

session1> SELECT firstname FROM names WHERE id = 7;
Bob

¿Tiene sentido?

Hazel_arun
fuente
Intenté la lectura repetible en SQL Server 2008 con "establecer la lectura repetible del nivel de aislamiento". Creó dos ventanas de consulta sql. Pero no funcionó. ¿Por qué?
Aditya Bokade
1
¿Por qué la segunda sesión1 aún leería a Aaron? ¿La transacción de session2 no está terminada y comprometida? Sé que esto es viejo, pero tal vez alguien pueda arrojar algo de luz.
Sonny Childs
99
Creo que la lectura repetible bloqueará la segunda sesión hasta que se confirme la primera sesión. Entonces el ejemplo está mal.
Nighon
44
En caso de lectura repetible, cuando la sesión 1 lee la fila, coloca un bloqueo compartido, que no permitiría ningún bloqueo exclusivo (a la sesión 2) para la actualización, por lo tanto, los datos no pueden actualizarse.
Taher
Creo que el servidor SQL y MySQL se comportan de manera diferente cuando se trata de actualizar filas compartidas entre dos transacciones
usuario2488286
23

Simplemente la respuesta de acuerdo con mi lectura y comprensión de este hilo y la respuesta @ remus-rusanu se basa en este escenario simple:

Hay dos procesos A y B. El proceso B está leyendo la Tabla X El proceso A está escribiendo en la tabla X El proceso B está leyendo nuevamente la Tabla X.

  • ReadUncommitted : el proceso B puede leer datos no confirmados del proceso A y puede ver diferentes filas según la escritura de B. No hay bloqueo en absoluto
  • ReadCommitted : el proceso B puede leer SOLO datos confirmados del proceso A y podría ver diferentes filas en función de la escritura B comprometida solamente. ¿podríamos llamarlo bloqueo simple?
  • RepeatableRead : el proceso B leerá los mismos datos (filas), independientemente de lo que esté haciendo el proceso A. Pero el proceso A puede cambiar otras filas. Bloque de nivel de filas
  • Serializable : el proceso B leerá las mismas filas que antes y el proceso A no puede leer ni escribir en la tabla. Bloque a nivel de tabla
  • Instantánea : cada proceso tiene su propia copia y están trabajando en ello. Cada uno tiene su propia vista.
Mo Zaatar
fuente
15

Antigua pregunta que ya tiene una respuesta aceptada, pero me gusta pensar en estos dos niveles de aislamiento en términos de cómo cambian el comportamiento de bloqueo en SQL Server. Esto podría ser útil para aquellos que están depurando puntos muertos como yo.

LEER COMPROMETIDO (predeterminado)

Los bloqueos compartidos se toman en SELECT y luego se liberan cuando se completa la instrucción SELECT . Así es como el sistema puede garantizar que no haya lecturas sucias de datos no confirmados. Otras transacciones aún pueden cambiar las filas subyacentes después de que su SELECT finalice y antes de que finalice su transacción.

LECTURA REPETIBLE

Los bloqueos compartidos se toman en SELECT y luego se liberan solo después de que se completa la transacción . Así es como el sistema puede garantizar que los valores que lea no cambiarán durante la transacción (porque permanecen bloqueados hasta que finaliza la transacción).

Chris Gillum
fuente
13

Tratando de explicar esta duda con diagramas simples.

Lectura confirmada: aquí, en este nivel de aislamiento, la transacción T1 leerá el valor actualizado de la X confirmada por la transacción T2.

Leer comprometido

Lectura repetible: en este nivel de aislamiento, la Transacción T1 no considerará los cambios confirmados por la Transacción T2.

ingrese la descripción de la imagen aquí

vkrishna17
fuente
1

Creo que esta imagen también puede ser útil, me ayuda como referencia cuando quiero recordar rápidamente las diferencias entre los niveles de aislamiento (gracias a kudvenkat en youtube)

ingrese la descripción de la imagen aquí

Ivan Pavičić
fuente
0

Tenga en cuenta que lo repetible en lectura repetible se refiere a una tupla, pero no a toda la tabla. En los niveles de aislamiento ANSC, puede ocurrir una anomalía de lectura fantasma , lo que significa leer una tabla con la misma cláusula donde dos veces puede devolver diferentes conjuntos de resultados diferentes. Literalmente, no es repetible .

不辞 长 做 岭南 人
fuente
-1

Mi observación sobre la solución inicial aceptada.

Bajo RR (mysql predeterminado): si un tx está abierto y se ha disparado un SELECT, otro tx NO puede eliminar ninguna fila que pertenezca al conjunto de resultados READ anterior hasta que se confirme el tx anterior (de hecho, la instrucción de borrado en el nuevo tx simplemente se bloqueará) , sin embargo, el siguiente tx puede eliminar todas las filas de la tabla sin ningún problema. Por cierto, una próxima LECTURA en tx anterior todavía verá los datos antiguos hasta que se confirmen.

Sanjeev Dhiman
fuente
2
Es posible que desee ponerlo en la sección de comentarios para que el respondedor sea notificado. De esa forma podrá responder a sus observaciones y hacer correcciones si es necesario.
RBT