2010-01-05 4 views
13

Todo lo que sé sobre esta excepción es de documentation de Spring y algunas publicaciones en el foro con desarrolladores frostrados que pegan enormes seguimientos de pila, y no hay respuestas.UnexpectedRollbackException - un análisis de escenario completo

De la documentación de primavera:

lanza cuando un intento de confirmar una transacción resultó en una reversión inesperada

quiero entender de una vez por todas

  1. Exactamente ¿Qué lo causa?

    • ¿Dónde se produjo la reversión? en el código del servidor de aplicaciones o en la base de datos?
    • ¿Se debe a una excepción subyacente específica (por ejemplo, algo de java.sql. *)?
    • ¿Está relacionado con Hibernate? ¿Está relacionado con Spring Transaction Manager (no es JTA en mi caso)?
  2. ¿Cómo evitarlo? ¿hay alguna mejor práctica para evitarlo?

  3. ¿Cómo se soluciona? parece ser difícil de reproducir, ¿alguna forma comprobada de solucionarlo?
+0

Eso particular, única excepción es lanzada en ciertas circunstancias específicas, desde dentro de la infraestructura Spring TX. ¿Qué mensaje estaba dentro de 'UnexpectedRollbackException'? Eso nos ayudará a rastrearlo. – skaffman

Respuesta

8

Desplácese un poco más atrás en el registro (o aumente el tamaño del búfer) y verá exactamente qué causó la excepción.

Si sucede que no está allí, verifique los métodos getMostSpecificCause() y getRootCause() de UnexpectedRollbackException - podrían ser útiles.

+4

Si los registros (con mayor tamaño de búfer) contenían la causa exacta, no lo habría estado preguntando aquí. Quiero entender los escenarios donde se lanza esta excepción. ¿Por qué mi configuración es relevante? una configuración de Hibernate + primavera muy común con HibernateTransactionManager por cierto –

+1

es un error común para omitir la causa fundamental de reversiones de transacción, porque es muy muy atrás en el StackTrace, y hay veces son consultas SQL emitidos en el medio. Le pedí su configuración porque de lo contrario, yo (o cualquier otra persona) no puedo adivinar qué podría estar causando esto. De todos modos, verifique mi respuesta actualizada para otra pista. – Bozho

+0

@Bozho - +1 para actualización, para aceptar una respuesta, quiero entender si la reversión ocurrió en la base de datos o en el servidor (por ejemplo, en el administrador de transacciones de software o en la base de datos a través de una excepción JDBC) tal vez ' ¿No estoy haciendo la pregunta correcta? –

11

Me pareció que este es contestar el resto de pregunta: https://jira.springsource.org/browse/SPR-3452

supongo que es necesario diferenciar entre transacción 'lógico' ámbitos y las transacciones físicas '' aquí ...

Lo PROPAGATION_REQUIRED crea un alcance de transacción lógica para cada método al que se aplica. Cada tal alcance de transacción lógica puede decidir individualmente sobre el estado de retrotraer solo, con una transacción externa siendo el alcance lógicamente independiente de el alcance interno de la transacción. Del curso , en el caso del comportamiento PROPAGATION_REQUIRED estándar , se asignarán a la misma transacción física a la misma transacción física . Por lo tanto, un marcador de solo retrotracción establecido en el alcance interno de la transacción afecta la probabilidad de la transacción externa de comprometerse realmente.Sin embargo, ya que el ámbito de transacción externa hizo no decidir sobre una reversión en sí, el rollback (silencio provocado por el alcance transacción interna) viene inesperado en ese nivel - que es por qué un UnexpectedRollbackException se tira.

PROPAGATION_REQUIRES_NEW, en contraste, utiliza una transacción completamente independiente para cada ámbito de transacción afectada . En ese caso, las transacciones físicas subyacentes serán diferentes y, por lo tanto, pueden confirmar o retrotraer de forma independiente, con una transacción externa que no se ve afectada por un estado de retrotracción de la transacción interna.

PROPAGATION_NESTED es diferente de nuevo en que utiliza una sola transacción física con múltiples puntos de retorno que puede volver a. Tales parciales rollbacks permiten un interior transacción alcance para desencadenar una reversión de su alcance , con la transacción exterior ser capaz de continuar la transacción física a pesar de algunas operaciones haber sido enrollado hacia atrás. Esto es típicamente mapeado en los puntos de guardado JDBC, , por lo que solo funcionará con las transacciones de recursos JDBC (Spring DataSourceTransactionManager).

Para completar la discusión: UnexpectedRollbackException puede también ser lanzada sin la aplicación cada vez haber establecido un marcador de reversión de sólo sí. En cambio, la infraestructura de la transacción puede haber decidido que el único resultado posible es una reversión , debido a restricciones en el estado de la transacción actual . Esto es particularmente relevante con XA transacciones.

Como he sugerido más arriba, lanzar una excepción en el interior de transacciones alcance, luego coger la excepción de que en el ámbito exterior y traducirlo en una llamada silenciosa setRollbackOnly no debe trabajar para su escenario. Un llamador de la transacción externa nunca verá una excepción. Dado que sólo preocuparse por esas reversiones silenciosas debido a los requisitos especiales impuestas por una persona que llama, yo incluso argumento que la solución arquitectónica correcta es utilizar excepciones dentro la capa de servicio, y para traducir esas excepciones en reversiones silenciosos en el nivel de fachada de servicio (derecha antes de volver a la llamada especial ).

Debido a que su problema no es posiblemente sólo alrededor de excepciones de rollback, pero más bien de cualquier excepción lanzada de su capa de servicios, que podría incluso utilizar estándar de excepción impulsada reversiones todo el camino a lo largo que capa de servicios, y luego coger y registrar tales excepciones vez que la transacción ya ha completado, de alguna fachada servicio adaptación que se traduce excepciones de su capa de servicio en la interfaz de usuario-error específico estados.

Juergen

3

Bueno te puedo decir cómo reproducir el UnexpectedRollbackException. Estaba trabajando en mi proyecto, y obtuve esta UnexpectedRollbackException en la siguiente situación. Tengo capas de control, servicio y dao en mi proyecto. Lo que hice es en mi clase de capa de servicio,

class SomeServiceClass { 
    void outerTransaction() { 
     // some lines of code 
     innerTransaction(); 
     //AbstractPlatformTransactionManager tries to commit but UnexpectedRollbackException is thrown, not here but in controller layer class that uses SomeServiceClass. 
    } 

    void innerTransaction() { 
     try { 
      // someDaoMethod or someDaoOperation that throws exception 
     } catch(Exception e) { 
      // when exception is caught, transaction is rolled back, outer transaction does not know about it. 
      // I got this point where inner transaction gets rolled back when I set HibernateTransactionManager.setFailEarlyOnGlobalRollbackOnly(true) 
      // FYI : use of following second dao access is wrong, 
      try { 
       // again some dao operation 
      } catch(Exception e1) { 
       throw e2; 
      } 
     } 
    } 
} 
Cuestiones relacionadas