E
Transactional en Spring: Propagación y Niveles de Aislamiento
jueves, 8 de enero de 202610 minutos

Transactional en Spring: Propagación y Niveles de Aislamiento

#Spring#@Transactional#Transacciones#Propagación#Aislamiento

Introducción a la Anotación @Transactional en Spring

La anotación @Transactional es una de las principales características del framework Spring, utilizada para gestionar transacciones de forma declarativa. Permite a los desarrolladores especificar cómo y cuándo debe iniciarse, comprometerse o revertirse una transacción.

En este tutorial, exploraremos en profundidad la propagación y los niveles de aislamiento de las transacciones en Spring, proporcionando ejemplos prácticos para ilustrar cada concepto.

¿Qué es la Propagación de Transacciones?

La propagación de transacciones se refiere a cómo se trata una transacción cuando un método anotado con @Transactional es llamado desde otro método también anotado con @Transactional. Spring proporciona varias opciones de propagación que definen el comportamiento de la transacción en diferentes escenarios.

Tipos de Propagación

A continuación, presentamos los principales tipos de propagación disponibles en Spring:

  • REQUIRED: Este es el comportamiento predeterminado. Si ya hay una transacción en curso, el método se ejecutará dentro de esa transacción. De lo contrario, se creará una nueva transacción.
  • REQUIRES_NEW: Siempre crea una nueva transacción, suspendiendo la transacción actual, si hay una. Esta opción es útil cuando necesitas garantizar que una operación se realice independientemente del estado de la transacción actual.
  • SUPPORTS: Si hay una transacción en curso, el método se ejecutará dentro de ella. De lo contrario, se ejecutará sin una transacción.
  • NOT_SUPPORTED: El método siempre se ejecutará fuera de una transacción, suspendiendo cualquier transacción en curso.
  • MANDATORY: El método debe ejecutarse dentro de una transacción. Si no hay una transacción en curso, se lanzará una excepción.
  • NEVER: El método debe ejecutarse fuera de una transacción. Si hay una transacción en curso, se lanzará una excepción.
  • NESTED: Si ya hay una transacción en curso, el método se ejecutará dentro de una transacción anidada. De lo contrario, si no hay transacción, se creará una nueva.

Ejemplo de Propagación

Consideremos un escenario donde tenemos dos servicios: ServicioA y ServicioB. El ServicioA llama a un método en el ServicioB. Veamos cómo podemos configurar la propagación:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ServicoA {
    @Transactional(propagation = Propagation.REQUIRED)
    public void metodoA() {
        // lógica del método A
        servicoB.metodoB();
    }
}

@Service
public class ServicoB {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void metodoB() {
        // lógica del método B
    }
}

En el ejemplo anterior, si se llama a metodoA y hay una transacción en curso, metodoB se ejecutará en una nueva transacción, independientemente del resultado de metodoA.

Niveles de Aislamiento de Transacciones

Los niveles de aislamiento definen cómo las transacciones interactúan entre sí. Controlan la visibilidad de los cambios realizados por una transacción para otras transacciones. Spring admite los siguientes niveles de aislamiento:

Tipos de Aislamiento

  • DEFAULT: Usa el nivel de aislamiento predeterminado de la base de datos.
  • READ_UNCOMMITTED: Permite que una transacción lea datos no confirmados de otra transacción. Esto puede llevar a lecturas sucias.
  • READ_COMMITTED: Garantiza que una transacción solo pueda leer datos confirmados. Evita lecturas sucias, pero puede resultar en lecturas no repetibles.
  • REPEATABLE_READ: Garantiza que una transacción pueda leer los mismos datos varias veces y obtener el mismo resultado. Esto evita lecturas no repetibles, pero puede llevar a fantasmas.
  • SERIALIZABLE: El nivel más alto de aislamiento, que garantiza que las transacciones estén completamente aisladas entre sí. Esto evita lecturas sucias, lecturas no repetibles y fantasmas, pero puede afectar el rendimiento.

Ejemplo de Nivel de Aislamiento

Ahora añadamos un nivel de aislamiento a nuestro ejemplo anterior:

import org.springframework.transaction.annotation.Isolation;

@Service
public class ServicoB {
    @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    public void metodoB() {
        // lógica del método B
    }
}

En el código anterior, el metodoB está configurado para usar el nivel de aislamiento READ_COMMITTED, garantizando que solo se lean datos confirmados.

Cuándo Usar Cada Tipo de Propagación y Aislamiento

Elegir el tipo de propagación y el nivel de aislamiento correctos depende del contexto de tu aplicación y de los requisitos de consistencia de datos.

  • REQUIRED: Usa cuando desees que los métodos se ejecuten dentro de la misma transacción, garantizando la atomicidad.
  • REQUIRES_NEW: Ideal para operaciones que no deben verse afectadas por una transacción padre, como registros de auditoría.
  • READ_COMMITTED: Es un buen equilibrio entre rendimiento y consistencia, evitando lecturas sucias.
  • SERIALIZABLE: Usa cuando la integridad de los datos es crítica y puedes tolerar la pérdida de rendimiento.

Conclusión

La anotación @Transactional en Spring es una herramienta poderosa para gestionar transacciones de manera efectiva. Comprender la propagación y los niveles de aislamiento es crucial para garantizar la integridad y consistencia de los datos en tus aplicaciones.

Intenta aplicar diferentes configuraciones de propagación y aislamiento en tus servicios para ver cómo afecta el comportamiento de las transacciones y el rendimiento de tu aplicación.

Call to Action

Si deseas profundizar tus conocimientos sobre Spring y transacciones, considera explorar la documentación oficial del Spring Framework y practicar con ejemplos en tus proyectos.

FAQ

¿Qué sucede si ocurre una excepción en un método anotado con @Transactional?

Si ocurre una excepción no verificada, la transacción se revertirá automáticamente. Para excepciones verificadas, debes configurar la anotación para que la transacción se revierta.

¿Puedo usar @Transactional en métodos privados?

No, la anotación @Transactional debe aplicarse en métodos públicos, ya que Spring utiliza proxies para aplicar la lógica de transacción.

¿Cuál es la diferencia entre @Transactional y la gestión de transacciones programática?

La anotación @Transactional permite una gestión declarativa, haciendo que el código sea más limpio y fácil de mantener, mientras que la gestión programática requiere más código y puede ser más propensa a errores.

¿Cómo puedo probar métodos anotados con @Transactional?

Puedes usar frameworks de prueba como JUnit y Spring Test para crear pruebas que verifiquen el comportamiento de las transacciones, asegurando que las operaciones se realicen correctamente.

¿Qué son las transacciones anidadas?

Las transacciones anidadas permiten que una transacción contenga otras transacciones. En Spring, esto se hace utilizando la propagación NESTED, permitiendo que solo reviertas la transacción interna si es necesario.


Author

Eridani Melo

Full Stack Developer