Descripción de los niveles de aislamiento
PostgreSQL tiene tres niveles de aislamiento de transacciones que impiden tres tipos de conflictos de simultaneidad, lecturas sucias, lecturas no repetibles y lecturas fantasma.
Tipos de conflictos de simultaneidad
Lecturas de datos sucios
Una lectura de datos sucios se produce cuando una transacción lee la versión actualizada de los datos que otra transacción está editando, Sin embargo, esta actualización nunca se confirma.
Por ejemplo, se produce una transacción en una cuenta de ahorro que haría que el saldo de la cuenta fuera inferior a cero. Antes de confirmar la transacción, se comprueba el saldo de cuenta y se revierte la transacción porque no se permite que las cuentas de ahorro tengan un saldo inferior a cero. Al mismo tiempo, se ejecuta un informe para mostrar el saldo actual de todas las cuentas de ahorro. Si se permiten las lecturas de datos sucios, se devolverá el saldo negativo, aunque nunca se confirme.
Lecturas no repetibles
Se produce una lectura no repetible si una transacción lee unos datos, otra transacción los actualiza y la transacción inicial vuelve a leer los datos y ve las nuevas actualizaciones.
Por ejemplo, la conexión A inicia una transacción y lee el costo por unidad y el número de unidades de un pedido (un costo de 10 USD y 3 unidades). Después, la conexión B inicia otra transacción y actualiza el mismo pedido para establecer el costo por unidad en 12. En la misma transacción de la consulta original, la conexión A calcula el coste total del pedido. Si se permiten las lecturas no repetibles, la conexión A devolverá el costo por unidad de 10, el número de unidades de 3 y el costo total de 36, lo que obviamente no tiene sentido.
Lecturas fantasma
Se produce una lectura fantasma si una transacción lee unos datos, otra transacción agrega una o varias filas nuevas a los datos y la transacción inicial vuelve a leer los datos y ve las nuevas actualizaciones.
Por ejemplo, la conexión A inicia una transacción y cuenta el número total de facturas por día en París. El recuento total es de 1100 facturas para las 10 tiendas de París. La conexión B inicia otra transacción y agrega una nueva tienda en París con 200 facturas en su día de apertura. En la transacción de la conexión A, el sistema ahora cuenta el número de tiendas para calcular el número de facturas por tienda. La conexión dividiría ahora las 1100 transacciones entre 11 tiendas en lugar de las 10 originales que existían cuando ejecutó la consulta de recuento de facturas. Este cálculo ahora devuelve un promedio incorrecto de 100 a pesar de que el nuevo almacén tenía 200 facturas que la transacción de la conexión A no tuvo en cuenta en su cálculo promedio.
Niveles de aislamiento
Azure Database for PostgreSQL tiene tres niveles de aislamiento de transacción: lectura confirmada, lectura repetible y serializable. La lectura no confirmada no está disponible en Azure Database for PostgreSQL.
A continuación se muestra cómo afectan los niveles de aislamiento a los conflictos de simultaneidad:
Nivel de aislamiento | Lectura desfasada | Lectura no repetible | Lectura fantasma |
---|---|---|---|
Lectura no confirmada* | Posibilidad | Posibilidad | Posibilidad |
Lectura confirmada | No es posible | Posibilidad | Posibilidad |
Lectura repetible | No es posible | No es posible | Posibilidad |
Serializable | No es posible | No es posible | No es posible |
* No disponible en PostgreSQL.
La lectura confirmada es el nivel de aislamiento predeterminado en Azure Database for PostgreSQL. La lectura confirmada es más adecuada para la mayoría de los escenarios, ya que impide las lecturas de datos sucios y, al mismo tiempo, proporciona un buen rendimiento. Es posible tener lecturas no repetibles y lecturas fantasma, pero estas condiciones solo pueden producirse si hay varias instrucciones SELECT consultando los mismos datos simultáneamente.
La lectura repetible difiere de la lectura confirmada porque varias instrucciones SELECT dentro de una transacción verían los mismos resultados incluso si otra transacción actualizara las filas entre la ejecución de las dos instrucciones SELECT de la transacción. Si otra transacción inserta filas nuevas, estas filas no aparecerían en los resultados de la segunda instrucción SELECT.
El nivel de aislamiento serializable proporciona el nivel más alto de aislamiento de transacción y funciona como si se ejecutaran transacciones diferentes en serie, es decir, una después de la otra. La desventaja del nivel de aislamiento serializable es que si una transacción realiza una actualización, otras transacciones podrían bloquearla. La transacción serializable tiene que esperar hasta que se complete la transacción de bloqueo, lo que afecta al rendimiento.
Las transacciones serializables tampoco pueden realizar cambios en las filas que otras transacciones modifican durante la transacción serializable. Si se produce este tipo de conflicto, se devuelve un mensaje de error. Por esta razón, es importante tener lógica de reintento integrada en las aplicaciones cuando se usan transacciones serializables.
Para actualizar los niveles de aislamiento de transacción, use el comando TRANSACTION ISOLATION LEVEL dentro de una transacción.
Por ejemplo:
BEGIN TRANSACTION
TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM humanresources.department
COMMIT;