tutorial proyecto mvc mediante framework formulario form español ejemplo desarrollo crear basico aplicaciones spring transactions

spring - proyecto - ¿por qué la transacción se revierte en RuntimeException pero no en SQLException?



spring mvc formulario ejemplo (3)

Este es el comportamiento definido. De la docs :

Cualquier RuntimeException desencadena la reversión, y cualquier excepción marcada no lo hace.

Este es un comportamiento común en todas las API de transacciones de Spring. De forma predeterminada, si se lanza una RuntimeException dentro del código transaccional, la transacción se retrotraerá. Si se lanza una excepción marcada (es decir, no es una excepción RuntimeException ), la transacción no se retrotraerá.

La razón detrás de esto es que las clases RuntimeException generalmente son tomadas por Spring para denotar condiciones de error irrecuperables.

Este comportamiento puede cambiarse del valor predeterminado, si lo desea, pero cómo hacerlo depende de cómo use la API de Spring y de cómo configure su administrador de transacciones.

Tengo un método de servicio administrado por Spring para administrar inserciones de base de datos. Contiene múltiples instrucciones de inserción.

@Transactional public void insertObservation(ObservationWithData ob) throws SQLException { observationDao.insertObservation(ob.getObservation()); // aop pointcut inserted here in unit test dataDao.insertData(ob.getData()); }

Tengo dos pruebas unitarias que arrojan una excepción antes de llamar al segundo inserto. Si la excepción es una excepción RuntimeException, la transacción se revierte. Si la excepción es una SQLException, la primera inserción se conserva.

Estoy desconcertado ¿Puede alguien decirme por qué la transacción no se revierte en una SQLException? ¿Alguien puede ofrecer una sugerencia de cómo manejar esto? Podría atrapar la SQLException y lanzar una RuntimeException, pero eso parece extraño.


Para @Transactional , de forma predeterminada, la reversión se produce solo en tiempo de ejecución, salvo excepciones sin @Transactional . Por lo tanto, su excepción SQLException comprobada no desencadena una reversión de la transacción; el comportamiento se puede configurar con los parámetros de anotación rollbackFor y noRollbackFor .

@Transactional(rollbackFor = SQLException.class) public void insertObservation(ObservationWithData ob) throws SQLException { observationDao.insertObservation(ob.getObservation()); // aop pointcut inserted here in unit test dataDao.insertData(ob.getData()); }


Spring hace un uso extensivo de RuntimeExceptions (incluido el uso de DataAccessExceptions para envolver SQLExceptions o excepciones de ORM) para los casos en los que no hay recuperación de la excepción. Se supone que desea utilizar excepciones comprobadas para los casos en que una capa que se encuentra por encima del servicio debe recibir una notificación de algo, pero no desea que se interfiera con la transacción.

Si está utilizando Spring, también puede hacer uso de sus bibliotecas de jdbc-wrapping y del servicio de traducción de excepción DataAccessException, reducirá la cantidad de código que debe mantener y proporcionará excepciones más significativas. También tener una capa de servicio que lanza excepciones específicas a la implementación es un mal olor. La forma anterior a Spring era crear excepciones comprobadas y sin aglomeraciones de la aplicación que encajaran con las excepciones específicas de la implementación, lo que resultó en una gran cantidad de trabajo ocupado y una base de código inflada. El camino de la primavera evita esos problemas.

Si desea saber por qué Spring optó por hacer que las cosas funcionen de esta manera, probablemente sea porque usan AOP para agregar el manejo de transacciones. No pueden cambiar la firma del método que están envolviendo, por lo que las excepciones comprobadas no son una opción.