2011-08-19 14 views
18

Tengo un método de servicio administrado por Spring para administrar las inserciones de la base de datos. Contiene múltiples instrucciones de inserción.por qué la transacción se retrotrae a RuntimeException pero no a SQLException

@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 de unidad que arrojan una excepción antes de llamar al segundo inserto. Si la excepción es una RuntimeException, la transacción se revierte. Si la excepción es una SQLException, la primera inserción se conserva.

Estoy desconcertado. ¿Alguien puede decirme por qué la transacción no retrocede en una SQLException? ¿Alguien puede ofrecer una sugerencia sobre cómo manejar esto? Pude captar la SQLException y lanzar una RuntimeException, pero eso parece extraño.

+2

Según la respuesta de skaffman y la sugerencia de Nathan, capturé todas las SQLExceptions en la capa DAO y utilicé SQLExceptionTranslator de Spring para traducirlas a DataAccessExceptions sin marcar. Esta publicación del foro de primavera, http://forum.springsource.org/showthread.php?63549-Conceptual-context-information, y el capítulo Manejo de errores de Robert Martin en "Código limpio. Un manual de software ágil para la artesanía" (Prentice Hall, 2008) también fueron útiles para aclarar por qué arrojar la excepción sin marcar mantiene una modularidad más agradable. – climmunk

Respuesta

35

Esto es un comportamiento definido. Desde el docs:

Cualquier RuntimeException desencadena rollback, y cualquier excepción revisada no lo hace.

Comportamiento habitual en todas las API de transacciones de Spring. De forma predeterminada, si se lanza un RuntimeException desde el código transaccional, la transacción se retrotraerá. Si se lanza una excepción marcada (es decir, no un RuntimeException), la transacción no se revertirá.

El razonamiento 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 predeterminado, si así lo desea, pero cómo hacerlo depende de cómo use Spring API y de cómo configure su administrador de transacciones.

+0

Sí, esto es correcto, aunque no entiendo completamente esto. Quiero arrojar la SQLException marcada para que el código de la aplicación pueda manejarla (log, move on, stop execution, etc.), pero no quiero que la transacción tenga éxito.Puedo configurar cada anotación de transacción para que se retrotraiga para la excepción, pero prefiero configurar el administrador de transacciones para que haga toda la aplicación. No es inmediatamente evidente que pueda configurar el DataSourceTransactionManager básico para hacer eso. Si tiene una sugerencia de una discusión más rica sobre esto, lo agradecería. Estoy buceando en los foros de primavera ahora. ¡Gracias! – climmunk

2

Spring hace un uso extenso de RuntimeExceptions (incluido el uso de DataAccessExceptions para ajustar SQLExceptions o excepciones de ORM) para los casos en que no hay recuperación de la excepción. Supone que desea utilizar excepciones comprobadas para los casos en que una capa superior al servicio necesita ser notificada de algo, pero no desea que se interfiera la transacción.

Si está utilizando Spring, también puede utilizar sus bibliotecas jdbc-wrapping y DataAccessException-tralating, reducirá la cantidad de código que debe mantener y proporcionará excepciones más significativas. Además, tener una capa de servicio arrojando excepciones específicas de la implementación es un mal olor. La forma anterior a Spring fue crear excepciones controladas por implementación que incluyan excepciones específicas de la implementación, esto dio como resultado 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 eligió hacer que las cosas funcionen de esta manera, es probablemente 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.

Cuestiones relacionadas