El isolation level o nivel de aislamiento es una de las configuraciones a nivel de base de datos que en ocasiones olvidamos establecer.
Podríamos decir que determina la forma en que los datos son "lockeados" o aislados de otros procesos mientras son accedidos, es decir, define como y cuando los cambios realizados por una transacción son visibles por otras operaciones concurrentes, influyendo en las siguientes anomalías:
Dirty Reads: Ocurre cuando una transacción lee datos modificados por otros procesos concurrentes que aún no han realizado commit, por eso se la denomina lectura sucia.
Nonrepeatable Reads: Ocurre cuando dentro de una transacción se lee el mismo registro mas de una vez y los datos obtenidos son diferentes, seguramente porque otro proceso concurrente los actualizó.
Phantom Reads: Ocurre cuando en una transacción ejecutamos el mismo query mas de una vez y obtenemos distintos resultados, por ejemplo si otra transacción agregó nuevos registros que satisfacen el criterio de búsqueda de la consulta.
El estándar ANSI/ISO SQL define cuatro niveles de aislamiento:
READ UNCOMMITTED: Permite que se produzcan Dirty Reads, Nonrepeatable Reads y PhantomReads. Es la opción menos restrictiva, recomendable si se manejan datos de solo lectura o muy pocas actualizaciones.
READ COMMITTED: Evita Dirty Reads, pero permite que se produzcan Nonrepeatable Reads y Phantom Reads.
REPEATABLE READ: Solo permite que se produzcan Phantom Reads.
SERIALIZABLE: Evita todos los casos anteriores, es la opción mas restrictiva.
Cada manejador de base de datos tiene su forma de configurar el isolation level a través de un administrador gráfico o por línea de comandos, por otro lado también es bueno aclarar que los productos difieren en los valores por defecto, por ejemplo en MySQL el default es REPEATABLE READ, en cambio en Oracle y SQL Server es READ COMMITTED.
Si usamos Hibernate como framework de persistencia podemos usar el property "hibernate.connection.isolation" en el hibernate.cfg.xml. Por ejemplo, para establecer la estrategia READ COMMITTED usaríamos:
<property name="hibernate.connection.isolation">2</property>Los valores posibles son los mismos que define la interface java.sql.Connection:
1: READ UNCOMMITTED
2: READ COMMITTED
4: REPEATABLE READ
8: SERIALIZABLE
Tener en cuenta la aclaración de la documentación oficial : "... note that most databases do not support all isolation levels". Ante la duda siempre lo mejor es hacer una prueba ejecutando dos transacciones en paralelo para verificar que tenemos el comportamiento esperado.
Hasta el próximo post!