Gestión de Transacciones en Jakarta EE: Lo básico
La gestión de transacciones es fundamental e integral en las aplicaciones empresariales para garantizar la preservación de la consistencia e integridad de los datos. Una transacción, desde el punto de vista de una base de datos, representa una unidad lógica de trabajo que abarca una o múltiples operaciones de base datos(insertar, update, borrar).
Jakarta EE, al igual que su predecesor JavaEE, ofrece una abstracción integral para gestionar transacciones, ya sea programáticamente a través de las API de JTA o de manera declarativa mediante anotaciones. Esta última es más popular debido a su simplicidad y la capacidad de mantener límites de transacción claros sin abrumar el código lógico del negocio. En este artículo, exploraremos la anotación @Transactional en Jakarta EE, y veremos diferentes comportamientos bajo varias configuraciones y algunas mejores prácticas.
La Anotación @Transactional
La anotación @Transactional es la que ofrece las capacidades de gestión de transacciones declarativas de Jakarta EE. Básicamente, cuando un método está decorado con @Transactional, Jakarta EE se asegura de que se inicie una transacción antes de la ejecución del método y posteriormente se confirme si la ejecución continúa normalmente, o se revierta si se produce una excepción.
Por defecto, la anotación @Transactional tiene un comportamiento de propagación REQUERIDO. Es decir, Si hay una transacción activa, únase a ella. Si no hay una transacción activa, inicie una nueva.
Vease:
https://jakarta.ee/specifications/transactions/2.0/apidocs/jakarta/transaction/transactional
Ejemplo:
@Stateless
public class MyService {
@Inject
private MyRepository repository;
@Transactional
public void performBusinessOperation() {
// lógica del negocio
repository.save(entity);
}
}Repository Code.
@Stateless
public class MyRepository {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void save(MyEntity entity) {
entityManager.persist(entity);
}
}En el ejemplo anterior, invocar performBusinessOperation() inicializa una nueva transacción. Cuando save() se llama posteriormente dentro de esa transacción, save() se une a la transacción existente en lugar de iniciar una nueva debido a su comportamiento de propagación REQUERIDO por defecto.
Sin embargo, vale la pena señalar que el uso superfluo de anotaciones @Transactional, especialmente cuando las transacciones ya están definidas en la capa de servicio, puede provocar confusión y comportamientos no anticipados. Por lo tanto, generalmente es una buena práctica definir transacciones a nivel de operaciones comerciales (como en la capa de servicio).
Manejo de errores (RollBack/Deshacer)
La anotacion @Transactional no es magica, hay alcances y caracteristicas que se deben manejar como el asilamiento de la persistencia de datos y el RollBack, esto se logra lanzando excpeciones del tipo Runtime, si usa una excepcion custom, esta debe heredar o ser del tipo Runtime.
Mejores Prácticas
Los límites de transacción deben reflejar los requisitos comerciales. Por lo general, es recomendable iniciar una nueva transacción para cada operación comercial distinta. Las demarcaciones de transacciones suelen ser mejor ubicadas en la capa de servicio, que se alinea bien con la comprensión de las operaciones comerciales. Por otro lado, anotar cada método a nivel de repositorio puede hacer que cada operación CRUD sea transaccional y, en consecuencia, puede crear una multitud de transacciones breves.
Sin embargo, vale la pena considerar el costo de una transacción. Cuanto más larga sea una transacción, más tiempo persistirán los bloqueos en los datos, limitando las posibilidades de acceso concurrente a los datos.
Conclusión
Todo lo que es entendible es hackeable: Un sólido entendimiento de las transacciones y @Transactional es indispensable para diseñar aplicaciones empresariales robustas. Seleccionar límites y configuraciones precisas para sus transacciones es crucial para mantener la integridad de los datos, el rendimiento y la escalabilidad de sus aplicaciones. Si bien Jakarta EE simplifica significativamente las complejidades de la gestión con la anotación @Transactional, ser consciente de sus comportamientos bajo diferentes configuraciones es crucial.

CTO en GInIEm S.A, Senior Software Engineer en Design House, Sr Software Engineer en Wepa. Master en Informática empresarial y consultor de Software con más de 12 años de experiencia.
Miembro del CORE del Java User Group Nicaragua, miembro organizador de Google Developer Group Nicaragua, Flutter Nicaragua y Flutter Latinoamérica. Conferencista internacional.
Entusiasta de Java y tecnologías móviles, ha trabajado con empresas de todo el mundo en el desarrollo de soluciones comerciales y de marketing que incluyen, entre otras, desarrollo back-end, desarrollo web / escritorio front-end, inteligencia empresarial y desarrollo móvil.
Disfruta de los desafíos y proyectos que exigen dar un esfuerzo adicional para lograr resultados extraordinarios.