Hace ya un tiempo, estuve mirando el funcionamiento de @Transaction en Spring, me di cuenta, que lo estaba usando mal o no estaba usando totalmente su potencial. Después de esto tuve que hacer una pequeña prueba. Esta pequeña prueba aseguró un poco más mis conocimientos sobre esta características de Spring.
Transacciones
Esta característica da soporte a la transacionalidad, sino tuvieras soporte de Spring, deberías inicializar tu la transacción con begin() y cerrarla con commit() o rollback() utilizando UserTransaction, de la siguiente manera:
public void transactionalPieceOfLogic() throws Exception {
userTransaction.begin();
boolean works = someBusinessLogic();
if(!works) {
userTransaction.rollback();
} else {
userTransaction.commit();
}
}
private boolean someBusinessLogic() {
this.moreBusinessLogic();
return true;
}
private void moreBusinessLogic() {
}
Pero este post, no es para explicar la transacción manual, cuando trabajamos con entidades. Para este blog, nos centraremos en el funcionamiento de @Transactional de Spring.
En mi experiencia laboral, he visto varios tipos de proyectos y la mayoría usaban la transacionalidad de manera estándar, de la siguiente manera:
@Transactional
public void transactionalPieceOfLogic() throws Exception {
Object someObject = someRepository.findAll();
Object objectModified = modifyObject(someObject);
someRepository.save(objectModified);
}
private Object modifyObject(Object object) {
//Some changes
}
Antes de continuar Propagación
Un aspecto muy interesante, es la propagación de la transaccionalidad a través de nuestra lógica de negocio. Por ejemplo, necesitamos un método transaccional, pero contemplamos la posibilidad de que exista una transacción superior, aún así queremos que esta transacción sea atómica y se ejecute de manera anidad. Para manejar este tipo de lógicas tan concretas tenemos la configuración de la propagación.
Cuando estéis desarrollando, no esta de más, entrar en las clases/interfaces y leer la documentación, que aporta el propio código, de Spring (en este caso), normalmente, os podréis descargar los sources del framework a través del soporte de vuestro IDE, con intellij es bastante sencillo.
Aunque en algunos casos, no podréis descargaros los sources y tendréis que ir directamente en el Javadoc si existe. Sino veréis la descompilación de la clase, pero con Spring no hay excusas.
Opciones de Propagación
REQUIRED: Da soporte a la transacción actual o crea una nueva sino existe.
SUPPORTS: Da soporte a la transacción actual, sino existe, ejecuta el método sin transacción.
MANDATORY: Da soporte a la transacción actual, sino existe, lanza una excepción.
REQUIRES_NEW: Crea una nueva transacción, si existe una, la suspende.
NOT_SUPPORTED: Ejecuta el método sin transacción, sí existe, la suspende.
NEVER: Ejecuta el método sin transacción, sí existe, lanza una excepción.
NESTED: Ejecuta dentro una transacción si existe una.
Transacción de solo lectura readOnly
Imaginaros que tenemos una entidad con un parámetro cómo «FetchType.Lazy» y un servicio en el cual, necesitamos acceder a esos datos, sólo para usarlos eventualmente. Tenemos dos opciones:
- Configurar los JPA graphs, para que, cuando lancemos un método concreto de nuestro repositorio, vuelva este Lazy > Eager. baeldung (seguramente escriba un post, pero aquí tenéis un ejemplo).
- Anotar el método como @Transactional(readOnly = true). Esto nos permitirá acceder a los métodos Lazy, sin problemas, utilizando el initizalize de hibernate
- Anotarlos con @Transactional.
Para ilustrar este post os traigo un ejemplo con Java. Si tenéis alguna duda y queréis que haga un poco más exhaustivo los ejemplo, comentar.
No necesitas de manera explicita el repository.save
Poca gente conoce esta particularidad y necesita poner de manera explicita la persistencia, tras la modificación.
Si nosotros. recuperamos una entidad de base de datos, con readOnly = false, lo cual es por defecto, y la modificamos, esta enitdad quedara modificada, tras salir del método sin necesidad de hacer el típico «save»
Ejemplo:
Escribe la leyenda…