En los sistemas de bases de datos , el aislamiento es una de las propiedades de transacción ACID ( atomicidad , consistencia , aislamiento, durabilidad ) . Determina cómo la integridad de la transacción es visible para otros usuarios y sistemas. Un nivel de aislamiento más bajo aumenta la capacidad de muchos usuarios para acceder a los mismos datos al mismo tiempo, pero también aumenta la cantidad de efectos de concurrencia (como lecturas sucias o actualizaciones perdidas ) que los usuarios pueden encontrar. Por el contrario, un nivel de aislamiento más alto reduce los tipos de efectos de concurrencia que los usuarios pueden encontrar, pero requiere más recursos del sistema y aumenta las posibilidades de que una transacción bloquee a otra. [1]
El control de concurrencia comprende los mecanismos subyacentes en un DBMS que manejan el aislamiento y garantizan la corrección relacionada. Es ampliamente utilizado por los motores de base de datos y almacenamiento tanto para garantizar la correcta ejecución de transacciones concurrentes como (a través de diferentes mecanismos) la corrección de otros procesos del DBMS. Los mecanismos relacionados con las transacciones normalmente restringen el tiempo de las operaciones de acceso a los datos de la base de datos ( programas de transacciones ) a ciertos órdenes caracterizados como las propiedades de programación de serialización y recuperabilidad . Restringir la ejecución de la operación de acceso a la base de datos normalmente significa un rendimiento reducido (medido por las tasas de ejecución) y, por lo tanto, los mecanismos de control de concurrencia normalmente están diseñados para proporcionar el mejor rendimiento posible bajo las restricciones. A menudo, cuando es posible sin dañar la corrección, la propiedad de serialización se compromete para un mejor rendimiento. Sin embargo, la recuperabilidad no se puede comprometer, ya que esto normalmente da como resultado una violación de la integridad de la base de datos .
El bloqueo en dos fases es el método de control de concurrencia de transacciones más común en los DBMS, que se utiliza para proporcionar serialización y capacidad de recuperación para la corrección. Para acceder a un objeto de base de datos, una transacción primero debe adquirir un bloqueo para este objeto. Según el tipo de operación de acceso (por ejemplo, leer o escribir un objeto) y el tipo de bloqueo, la adquisición del bloqueo puede bloquearse y posponerse si otra transacción mantiene un bloqueo para ese objeto.
El aislamiento se aplica normalmente en el nivel de la base de datos. Sin embargo, también se pueden utilizar varios sistemas del lado del cliente. Se puede controlar en los marcos de aplicación o en contenedores de tiempo de ejecución como los J2EE Entity Beans [2] . En sistemas más antiguos, se puede implementar de forma sistémica (por los desarrolladores de la aplicación), por ejemplo, mediante el uso de tablas temporales. [ verificación fallida ] En aplicaciones web de dos niveles, tres niveles o n niveles , se puede utilizar un gestor de transacciones para mantener el aislamiento. Un gestor de transacciones es un middleware que se encuentra entre un servicio de aplicación (servicio de aplicación back-end) y el sistema operativo. Un gestor de transacciones puede proporcionar aislamiento global y atomicidad. Realiza un seguimiento de cuándo se unen nuevos servidores a una transacción y coordina un protocolo de confirmación atómica entre los servidores. Los detalles se abstraen de la aplicación, lo que hace que las transacciones sean más sencillas y fáciles de codificar. Un monitor de procesamiento de transacciones (TPM) es una colección de middleware que incluye un gestor de transacciones. Un TPM puede proporcionar aislamiento local a una aplicación con un gestor de bloqueos. [2]
El estándar ANSI/ISO SQL 92 se refiere a tres fenómenos de lectura diferentes cuando una transacción recupera datos que otra transacción podría haber actualizado.
En los siguientes ejemplos, se llevan a cabo dos transacciones. En la transacción 1 se realiza una consulta, luego en la transacción 2 se realiza una actualización y, por último, en la transacción 1 se vuelve a realizar la misma consulta.
Los ejemplos utilizan la siguiente relación:
Una lectura sucia (también conocida como dependencia no confirmada ) ocurre cuando una transacción recupera una fila que ha sido actualizada por otra transacción que aún no está confirmada.
En este ejemplo, la transacción 1 recupera la fila con id 1, luego la transacción 2 actualiza la fila con id 1 y, finalmente, la transacción 1 recupera nuevamente la fila con id 1. Ahora, si la transacción 2 revierte su actualización (ya recuperada por la transacción 1) o realiza otras actualizaciones, la vista de la fila puede ser incorrecta en la transacción 1. En el nivel de aislamiento READ UNCOMMITTED, el segundo SELECT en la transacción 1 recupera la fila actualizada: esta es una lectura sucia. En los niveles de aislamiento READ COMMITTED, REPEATABLE READ y SERIALIZABLE, el segundo SELECT en la transacción 1 recupera la fila inicial.
Una lectura no repetible ocurre cuando una transacción recupera una fila dos veces y esa fila es actualizada por otra transacción que se confirma en el medio.
En este ejemplo, la transacción 1 recupera la fila con id 1, luego la transacción 2 actualiza la fila con id 1 y se confirma, y finalmente la transacción 1 recupera nuevamente la fila con id 1. En los niveles de aislamiento READ UNCOMMITTED y READ COMMITTED, el segundo SELECT en la transacción 1 recupera la fila actualizada: esta es una lectura no repetible. En los niveles de aislamiento REPEATABLE READ y SERIALIZABLE, el segundo SELECT en la transacción 1 recupera la fila inicial.
Una lectura fantasma ocurre cuando una transacción recupera un conjunto de filas dos veces y otra transacción que se confirma en el medio inserta o elimina filas nuevas de ese conjunto.
En este ejemplo, la transacción 1 recupera el conjunto de filas con una edad mayor a 17, luego la transacción 2 inserta una fila con una edad de 26 y se confirma, y finalmente la transacción 1 recupera nuevamente el conjunto de filas con una edad mayor a 17. En los niveles de aislamiento READ UNCOMMITTED, READ COMMITTED y REPEATABLE READ, el segundo SELECT en la transacción 1 recupera el nuevo conjunto de filas que incluye la fila insertada: esta es una lectura fantasma. En el nivel de aislamiento SERIALIZABLE, el segundo SELECT en la transacción 1 recupera el conjunto inicial de filas.
Existen dos estrategias básicas que se utilizan para evitar lecturas no repetibles y lecturas fantasma. En la primera estrategia, el control de concurrencia basado en bloqueos , la transacción 2 se confirma después de que la transacción 1 se confirma o se revierte. Produce el programa serial T1, T2 . En la otra estrategia, el control de concurrencia multiversión , la transacción 2 se confirma inmediatamente mientras que la transacción 1, que comenzó antes de la transacción 2, continúa operando en una instantánea antigua de la base de datos tomada al comienzo de la transacción 1, y cuando la transacción 1 finalmente intenta confirmarse, si el resultado de la confirmación sería equivalente al programa serial T1, T2 , entonces se confirma la transacción 1; de lo contrario, hay un conflicto de confirmación y la transacción 1 se revierte con un error de serialización.
En el control de concurrencia basado en bloqueos, pueden producirse lecturas no repetibles y lecturas fantasma cuando no se adquieren bloqueos de lectura al realizar una operación SELECT, o cuando los bloqueos adquiridos en las filas afectadas se liberan tan pronto como se realiza la operación SELECT. En el control de concurrencia multiversión, pueden producirse lecturas no repetibles y lecturas fantasma cuando se relaja el requisito de que se debe revertir una transacción afectada por un conflicto de confirmación.
De las cuatro propiedades ACID de un DBMS (sistema de gestión de bases de datos), la propiedad de aislamiento es la que se relaja con más frecuencia. Cuando se intenta mantener el nivel más alto de aislamiento, un DBMS suele adquirir bloqueos en los datos que pueden provocar una pérdida de concurrencia o implementar un control de concurrencia multiversión . Esto requiere agregar lógica para que la aplicación funcione correctamente.
La mayoría de los DBMS ofrecen una serie de niveles de aislamiento de transacciones , que controlan el grado de bloqueo que se produce al seleccionar datos. Para muchas aplicaciones de bases de datos, la mayoría de las transacciones de bases de datos se pueden construir para evitar la necesidad de altos niveles de aislamiento (por ejemplo, el nivel SERIALIZABLE), lo que reduce la sobrecarga de bloqueo para el sistema. El programador debe analizar cuidadosamente el código de acceso a la base de datos para asegurarse de que cualquier relajación del aislamiento no provoque errores de software que sean difíciles de encontrar. Por el contrario, si se utilizan niveles de aislamiento más altos, aumenta la posibilidad de bloqueo , lo que también requiere un análisis cuidadoso y técnicas de programación para evitarlo.
Dado que cada nivel de aislamiento es más fuerte que los inferiores, en el sentido de que ningún nivel de aislamiento superior permite una acción prohibida por uno inferior, el estándar permite que un DBMS ejecute una transacción en un nivel de aislamiento más fuerte que el solicitado (por ejemplo, una transacción de "Lectura confirmada" puede en realidad realizarse en un nivel de aislamiento de "Lectura repetible").
Los niveles de aislamiento definidos por el estándar ANSI / ISO SQL se enumeran a continuación.
Este es el nivel de aislamiento más alto .
Con una implementación de DBMS de control de concurrencia basado en bloqueos , la serialización requiere que los bloqueos de lectura y escritura (adquiridos en los datos seleccionados) se liberen al final de la transacción. También se deben adquirir bloqueos de rango cuando una consulta SELECT utiliza una cláusula WHERE de rango , especialmente para evitar el fenómeno de lecturas fantasma .
Cuando se utiliza un control de concurrencia sin bloqueos, no se adquieren bloqueos; sin embargo, si el sistema detecta una colisión de escritura entre varias transacciones simultáneas, solo se permite confirmar una de ellas. Consulte el aislamiento de instantáneas para obtener más detalles sobre este tema.
De: (Segundo borrador de revisión informal) ISO/IEC 9075:1992, Lenguaje de base de datos SQL - 30 de julio de 1992: Se garantiza que la ejecución de transacciones SQL concurrentes en el nivel de aislamiento SERIALIZABLE es serializable. Una ejecución serializable se define como una ejecución de las operaciones de transacciones SQL que se ejecutan simultáneamente y que produce el mismo efecto que alguna ejecución serial de esas mismas transacciones SQL. Una ejecución serial es aquella en la que cada transacción SQL se ejecuta hasta su finalización antes de que comience la siguiente transacción SQL.
En este nivel de aislamiento, una implementación de DBMS de control de concurrencia basado en bloqueos mantiene los bloqueos de lectura y escritura (adquiridos en datos seleccionados) hasta el final de la transacción. Sin embargo, los bloqueos de rango no se administran, por lo que pueden ocurrir lecturas fantasma .
En algunos sistemas, es posible que se produzcan sesgos de escritura en este nivel de aislamiento. Se trata de un fenómeno en el que dos escritores diferentes (que ya leyeron las columnas que están actualizando) permiten dos operaciones de escritura en las mismas columnas de una tabla, lo que da como resultado que la columna tenga datos que son una mezcla de las dos transacciones. [3] [4]
En este nivel de aislamiento, una implementación de DBMS de control de concurrencia basado en bloqueos mantiene los bloqueos de escritura (adquiridos en los datos seleccionados) hasta el final de la transacción, pero los bloqueos de lectura se liberan tan pronto como se realiza la operación SELECT (por lo que el fenómeno de lecturas no repetibles puede ocurrir en este nivel de aislamiento). Al igual que en el nivel anterior, los bloqueos de rango no se administran.
En otras palabras, la lectura confirmada es un nivel de aislamiento que garantiza que cualquier dato leído se confirme en el momento en que se lee. Simplemente impide que el lector vea cualquier lectura intermedia, no confirmada y "sucia". No promete en absoluto que si la transacción vuelve a emitir la lectura, encontrará los mismos datos; los datos pueden cambiar después de leerse.
Este es el nivel de aislamiento más bajo . En este nivel, se permiten lecturas sucias , por lo que una transacción puede ver cambios no confirmados realizados por otras transacciones.
El nivel de aislamiento predeterminado de los distintos DBMS varía considerablemente. La mayoría de las bases de datos que incluyen transacciones permiten al usuario configurar cualquier nivel de aislamiento. Algunos DBMS también requieren sintaxis adicional al ejecutar una instrucción SELECT para adquirir bloqueos (por ejemplo, SELECT… FOR UPDATE para adquirir bloqueos de escritura exclusivos en las filas a las que se accede).
Sin embargo, las definiciones anteriores han sido criticadas por ser ambiguas y por no reflejar con precisión el aislamiento que proporcionan muchas bases de datos:
También hay otras críticas sobre la definición de aislamiento de ANSI SQL, ya que alienta a los implementadores a hacer "cosas malas":
La serialización de anomalías no es lo mismo que la serialización. Es decir, es necesario, pero no suficiente, que una programación serializable esté libre de los tres tipos de fenómenos. [5]
¡Vea más arriba, en el minuto 13:30 del webcast!)