1. Información general
Este tutorial discutirá la forma correcta de configurar Spring Transactions , cómo usar la anotación @Transactional y los errores comunes.
Para una discusión más profunda sobre la configuración de persistencia principal, consulte el tutorial de Spring con JPA.
Básicamente, hay dos formas distintas de configurar las transacciones: anotaciones y AOP, cada una con sus propias ventajas. Vamos a discutir la configuración de anotación más común aquí.
2. Configurar transacciones
Spring 3.1 presenta la anotación @EnableTransactionManagement que podemos usar en una clase @Configuration y habilitar el soporte transaccional:
@Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ //... } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() ); return transactionManager; } }
Sin embargo, si estamos usando un proyecto Spring Boot y tenemos dependencias spring-data- * o spring-tx en la ruta de clases, la administración de transacciones estará habilitada de forma predeterminada .
3. Configurar transacciones con XML
Antes de 3.1 o si Java no es una opción, aquí está la configuración XML, usando anotaciones y el soporte de espacio de nombres:
4. La anotación @Transactional
Con las transacciones configuradas, ahora podemos anotar un bean con @Transactional ya sea a nivel de clase o de método:
@Service @Transactional public class FooService { //... }
La anotación también admite configuraciones adicionales :
- el tipo de propagación de la transacción
- el nivel de aislamiento de la transacción
- un tiempo de espera para la operación envuelta por la transacción
- un indicador readOnly : una sugerencia para el proveedor de persistencia de que la transacción debe ser de solo lectura
- las reglas de reversión para la transacción
Tenga en cuenta que, de forma predeterminada, la reversión ocurre durante el tiempo de ejecución, solo con excepciones no marcadas. La excepción marcada no desencadena una reversión de la transacción. Por supuesto, podemos configurar este comportamiento con los parámetros de anotación rollbackFor y noRollbackFor .
5. Posibles obstáculos
5.1. Transacciones y poderes
En un nivel alto, Spring crea proxies para todas las clases anotadas con @Transactional , ya sea en la clase o en cualquiera de los métodos. El proxy permite que el marco inyecte lógica transaccional antes y después del método de ejecución, principalmente para iniciar y confirmar la transacción.
Lo que es importante tener en cuenta es que, si el bean transaccional está implementando una interfaz, por defecto el proxy será un Java Dynamic Proxy. Esto significa que solo se interceptarán las llamadas a métodos externos que entren a través del proxy. Cualquier llamada de auto-invocación no iniciará ninguna transacción, incluso si el método tiene la anotación @Transactional .
Otra advertencia del uso de proxies es que solo los métodos públicos deben anotarse con @Transactional. Los métodos de cualquier otra visibilidad simplemente ignorarán la anotación en silencio, ya que no son proxy.
En este artículo, se analizan con gran detalle más trampas de proxy.
5.2. Cambio del nivel de aislamiento
También podemos cambiar el nivel de aislamiento de la transacción:
@Transactional(isolation = Isolation.SERIALIZABLE)
Tenga en cuenta que esto se ha introducido en Spring 4.1; si ejecutamos el ejemplo anterior antes de Spring 4.1, resultará en:
org.springframework.transaction.InvalidIsolationLevelException : JPA estándar no admite niveles de aislamiento personalizados; use un JpaDialect especial para su implementación de JPA
5.3. Transacciones de solo lectura
El indicador readOnly generalmente genera confusión, especialmente cuando se trabaja con JPA; desde el Javadoc:
Esto solo sirve como una pista para el subsistema de transacciones real; será no necesariamente causar fracaso de los intentos de acceso de escritura. Un administrador de transacciones que no pueda interpretar la sugerencia de solo lectura no lanzará una excepción cuando se le solicite una transacción de solo lectura.
El hecho es que no podemos estar seguros de que no se produzca una inserción o actualización cuando se establece el indicador readOnly . Este comportamiento depende del proveedor, mientras que JPA es independiente del proveedor.
También es importante comprender que la marca readOnly solo es relevante dentro de una transacción. Si una operación ocurre fuera de un contexto transaccional, la bandera simplemente se ignora. Un ejemplo simple de eso llamaría a un método anotado con:
@Transactional( propagation = Propagation.SUPPORTS,readOnly = true )
desde un contexto no transaccional: no se creará una transacción y se ignorará el indicador readOnly .
5.4. Registro de transacciones
Un método útil para comprender los problemas relacionados con las transacciones es ajustar el registro en los paquetes transaccionales. El paquete relevante en Spring es " org.springframework.transaction", que debe configurarse con un nivel de registro de TRACE.
6. Conclusión
Cubrimos la configuración básica de la semántica transaccional usando Java y XML, cómo usar @Transactional y las mejores prácticas de una estrategia transaccional.
Como siempre, el código presentado en este artículo está disponible en Github.