2010-12-09 11 views
18

referencia a Spring documentation:Mejores prácticas para hacer retroceder las transacciones en la primavera de 3/Hibernate

Cualquier RuntimeException activarán rollback, y cualquier excepción revisada no

referencia a javapractices.com

sin comprobar excepciones:

  • representan defectos en el programa (errores) - a menudo argumentos inválidos pasaron a un método no privado. Para cita de la programación en Java Idioma, por Gosling, Arnold, y Holmes: "excepciones de tiempo de ejecución sin comprobar representan condiciones que, en general habla, reflejar errores en la lógica de su programa de y no puede ser razonablemente recuperado de durante la ejecución tiempo "
  • son subclases de RuntimeException, y por lo general se implementan usando IllegalArgumentException, NullPointerException, o IllegalStateException
  • un método no está obligado a establecer una política para las excepciones sin marcar lanzadas por su aplicación (y casi siempre no lo hacen de modo)

las excepciones comprobadas:

  • representan condiciones no válidas en áreas fuera de la estafa inmediata trol de el programa (de entrada no válido de usuario, problemas de bases de datos, las interrupciones de red, archivos ausentes)
  • son subclases de Excepción
  • un método está obligado a establecer una política para todas las excepciones lanzadas por su aplicación seleccionada (ya sea pasar la excepción comprobada más arriba la pila, o manejar de alguna manera)

Si durante mi lógica de negocio descubro un problema y quiero deshacer los cambios, tengo que lanzar una nueva Run timeException? No es realmente una excepción RuntimeException (excepción no verificada) ya que la identifiqué en la lógica. ¿O tal vez estoy malinterpretando estos conceptos?

Mi pregunta real, ¿cuáles son las mejores prácticas para deshacer una transacción en mis métodos de servicio @Transactional?

Respuesta

10

Si está utilizando excepciones simplemente añadirlos a la propiedad de su rollbackFor@Transactional anotación marcada.

@Transactional(rollbackFor = { MyInvalidUserException.class, MyApplicationException.class }) 
public void method() throws MyInvalidUserException, MyApplicationException { 
    ... 
    ... 
} 

etc.

org.life.java La respuesta también funciona bien. Es una decisión académica si desea entremezclar la administración de transacciones programáticas en sus transacciones declarativas o mantenerla estrictamente declarativa.

+1

¿Cómo puedo devolver algo de mi método si tiro? ¿una excepción? Además, lanzar una excepción es bastante costoso. ¿No hay alguna manera de deshacer manualmente la transacción sin activar una excepción? –

+0

@GuillaumePolet Podría decirse que si está invirtiendo deliberadamente las cosas como parte de un flujo de procesos comerciales no excepcionales, los costos asociados con las reversiones en un RDBMS empequeñecen por órdenes de magnitud cualquier costo real o percibido de una excepción en un entorno moderno JVM, y todo el diseño debería ser revisado. De todos modos, si no te gusta la forma en que funcionan las transacciones declarativas ... no las uses. La característica no es de ninguna manera su única opción. Aún puede usar transacciones simples de sesión de hibernación propias. – Affe

4

Debe ser como

@Transactional 
public void method() throws YourCustomException { 
    try{ 
      //logic 
    }catch(Exception ex){ 
      TransactionAspectSupport.currentTransactionStatus() 
         .setRollbackOnly(); 
      throw(new YourCustomException(ex.getMessage())); 
    } 
} 
+5

... y * por qué * debería ser así? – meriton

+0

@meriton Funcionará para todo el caso, me refiero a que su propósito de demostrar que este servicio arroja esta excepción se resolverá, así como también se atenderán sus asuntos transaccionales –

2

Creo que es seguro decir que hay opiniones diferentes sobre las excepciones que deben verificarse. Por ejemplo, considere este extracto de Introduction to the Spring Framework:

Los datos de Primavera de acceso de excepción jerarquía se basa en excepciones (tiempo de ejecución) sin marcar. Después de haber trabajado con Spring en varios proyectos estoy cada vez más convencido de que esto fue la decisión correcta.

Excepciones de acceso a los datos no generalmente recuperables. Por ejemplo, si no podemos conectarnos a la base de datos, no es posible que un objeto de negocio en particular resuelva el problema. Una excepción posible es optimista violaciónes de bloqueo, pero no todas las aplicaciones utilizan bloqueo optimista. Por lo general, es malo tener que escribir el código para detectar excepciones fatales que no se pueden manejar con sensatez. Permitir que se propaguen a los controladores de nivel superior como el servlet o contenedor EJB es generalmente más apropiado. Todas las excepciones de acceso a datos de Spring son subclases de DataAccessException, por lo que si hacemos escogemos capturar todas las excepciones de acceso a datos de Spring , podemos hacerlo fácilmente.

Tenga en cuenta que si queremos recuperar de una excepción de acceso a los datos sin marcar , aún podemos hacerlo. Podemos escribir código para manejar solo la condición recuperable . Por ejemplo, si consideramos que sólo un optimista violación de bloqueo es recuperable, que podemos escribir código en un DAO primavera como sigue:

try {// hacer el trabajo } catch (OptimisticLockingFailureException ex) { // Estoy interesado en esto} Si Las excepciones de acceso a datos de Spring fueron marcadas, tendremos que escribir el código siguiente de . Tenga en cuenta que podríamos optar por escribir esto de todos modos:

try {// hacer el trabajo } catch (OptimisticLockingFailureException ex) {// Estoy interesado en este } catch (DataAccessException ex) {// fatal; simplemente vuelva a lanzarlo} Una objeción potencial al primer ejemplo - que el compilador no puede forzar el manejo la excepción potencialmente recuperable - se aplica también al segundo. Como estamos obligados a detectar la excepción base (DataAccessException), el compilador no aplicará una comprobación para una subclase (OptimisticLockingFailureException). Así que el compilador nos obligaría a escribir el código para manejar un problema irrecuperable , pero no proporcionar ayuda en forzándonos a ocuparnos del problema recuperable .

uso de primavera de acceso a datos sin control excepciones es consistente con la de muchos - probablemente la mayoría - exitosas frameworks de persistencia. (De hecho, fue en parte inspirado por JDO.) JDBC es una de las pocas API de acceso a datos para usar excepciones verificadas . TopLink y JDO, por ejemplo, usan excepciones sin marcar exclusivamente. Hibernate cambió de comprobado a excepciones sin marcar, en la versión 3.

las excepciones de acceso de datos están claramente fuera del control inmediato del programa, por lo que de acuerdo a javapractices, que debe ser revisado. Pero las personas en la fuente de primavera difieren. Y confío en su juicio más que en las prácticas de Java.

Por lo tanto, no veo nada de malo en lanzar una excepción no comprobada para indicar que la transacción se debe revertir. Por supuesto, también puede usar excepciones controladas y configurar el aspecto para que también se retrotraigan. (Véase la respuesta de Affe para más detalles)

6

Cualquiera de hacer retroceder mediante programación desde dentro:

@Transactional 
public void commit() { 
    try { 
    // some business logic... 
    } catch (ConstraintViolationException e) { 
    // trigger rollback programmatically 
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 
    } 
} 

o marcar la excepción para la restitución y manejarlo de la persona que llama:

@Transactional(rollBackFor = TransactionException.class) 
public void commit() throws ConstraintViolationException{ 
    try { 
    // some business logic... 
    } catch (ConstraintViolationException e) { 
    // handle the exception 
    // re-throw for rollback 
    new TransactionException(e); 
    } 
} 

public void doCommit(){ 
    try { 
    commit() 
    } catch (TransactionException e){ 
    // do nothing as already handled 
    } 
} 

Yo prefiero la primera, ya que mantiene el código es más simple, pero es discouraged según los documentos de Spring:

La reversión programática está disponible en caso de que la necesite, pero su uso va en contra de lograr una arquitectura limpia basada en POJO .

Cuestiones relacionadas