Propiedades ACID y Spring Data: Uso de @Transactional

Clase 21 de 25Curso de Java Spring Data JPA: Bases de Datos

Contenido del curso

Spring Data Repositories

Resumen

Garantizar que cada operación en la base de datos se complete de forma íntegra es uno de los pilares de cualquier aplicación robusta. Cuando trabajamos con Spring Data JPA, la anotación @Transactional se convierte en la herramienta clave para proteger la integridad de la información y asegurar que ninguna transacción quede a medias.

¿Qué significan las propiedades ACID en una base de datos?

El acrónimo ACID agrupa cuatro propiedades que toda transacción confiable debe cumplir [0:10]:

  • Atomicidad: todo o nada. Si ocurre un error a mitad del proceso, se ejecuta un rollback que devuelve la información a su estado inicial. Solo si la transacción completa es exitosa, los datos quedan persistidos.
  • Consistencia: únicamente se permiten operaciones que respeten la integridad referencial. No se pueden usar, por ejemplo, foreign keys que apunten a claves primarias inexistentes en otras tablas [0:48].
  • Aislamiento (isolation): cada transacción se ejecuta de forma independiente respecto a otras que estén ocurriendo simultáneamente, evitando que la información se mezcle o quede incompleta [1:06].
  • Durabilidad (durability): los datos deben ser persistentes en el tiempo. Si la base de datos se reinicia, la información de transacciones previas debe seguir existiendo [1:22].

Estas cuatro características trabajan en conjunto para que la capa de datos sea predecible y segura.

¿Cómo funciona la anotación @Transactional en Spring Data?

Al anotar un método con @Transactional, Spring garantiza automáticamente las propiedades ACID [1:40]. Es especialmente importante usarla cuando un mismo método realiza dos o más llamados a la base de datos, ya que agrupa todas las operaciones en una sola transacción atómica.

¿Qué ocurre cuando falla una operación dentro de la transacción?

Imagina un método que primero actualiza el precio de una pizza y después intenta enviar un correo electrónico informando el cambio. Si el envío del email falla —por ejemplo, el API no está disponible— y la anotación @Transactional está presente, toda la transacción hace rollback, incluyendo la actualización de precio [2:30].

Para simular este escenario se crea una excepción personalizada llamada EmailApiException que extiende de RuntimeException [3:02]:

java public class EmailApiException extends RuntimeException { public EmailApiException() { super("Error sending email"); } }

Dentro del servicio, un método privado sendEmail() lanza esta excepción. Al ejecutar la petición PUT para cambiar el precio, el servidor devuelve un 500 Internal Server Error y el precio permanece sin cambios gracias al rollback automático [4:20].

¿Cómo evitar el rollback en excepciones específicas con noRollbackFor?

En muchos casos, un error al enviar un correo no debería revertir la actualización de precio, porque son procesos independientes. Para resolver esto, @Transactional ofrece el atributo noRollbackFor [5:08]:

java @Transactional(noRollbackFor = EmailApiException.class) public void updatePrice(PizzaEntity pizza) { // actualizar precio // enviar email }

Con esta configuración, si ocurre una EmailApiException, la transacción confirma los cambios en la base de datos. Si ocurre cualquier otra excepción, sí ejecutará el rollback. Al probar nuevamente, el servidor devuelve un error 500 por el email, pero al consultar la pizza se verifica que el precio sí se actualizó correctamente [5:40].

¿Qué es la propagación en @Transactional y cuáles son sus tipos?

Otro atributo relevante es propagation, que define cómo se comporta la transacción respecto a otras ya existentes [6:10]:

  • REQUIRED (por defecto): si ya existe una transacción, se une a ella; si no existe, crea una nueva.
  • MANDATORY: exige que ya exista una transacción activa. Si no la encuentra, lanza una excepción en lugar de crearla.

Existen otros tipos de propagación como SUPPORTS, REQUIRES_NEW, NOT_SUPPORTED y NEVER, cada uno con comportamientos específicos según el contexto de ejecución.

Usar @Transactional de manera consciente es una práctica esencial para construir aplicaciones confiables con Spring Data JPA. Si has trabajado con escenarios donde el rollback selectivo te salvó de problemas, comparte tu experiencia en los comentarios.