example entitymanagerfactory data java hibernate spring exception

java - entitymanagerfactory - UnexpectedRollbackException-un análisis de escenario completo



spring java orm (3)

Todo lo que sé sobre esta excepción es de la documentation de Spring y algunas publicaciones del foro con desarrolladores frostrados que pegan enormes trazas de pila y no respuestas.

De la documentación de primavera:

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

Quiero entender de una vez por todas

  1. ¿Exactamente qué lo causa?

    • ¿Dónde ocurrió el retroceso? ¿En el código del Servidor de Aplicaciones o en la Base de Datos?
    • ¿Se debió a una excepción subyacente específica (por ejemplo, algo de java.sql. *)?
    • ¿Está relacionado con la hibernación? ¿Está relacionado con Spring Transaction Manager (no JTA en mi caso)?
  2. ¿Cómo evitarlo? ¿Hay alguna mejor práctica para evitarlo?

  3. ¿Cómo depurarlo? Parece ser difícil de reproducir, ¿hay alguna forma comprobada de solucionarlo?

Bueno, te puedo decir cómo reproducir la excepción UnexpectedRollbackException. Estaba trabajando en mi proyecto y obtuve esta UnexpectedRollbackException en la siguiente situación. Estoy teniendo controlador, servicio y capas de dao en mi proyecto. Lo que hice está 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; } } } }


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

Si sucede que no está allí, verifique los getMostSpecificCause() y getRootCause() de UnexpectedRollbackException ; pueden ser útiles.


Encontré que esto estaba respondiendo el resto de la pregunta: https://jira.springsource.org/browse/SPR-3452

Supongo que necesitamos diferenciar entre los ámbitos de transacción "lógicos" y las transacciones "físicas" aquí ...

Lo que crea PROPAGATION_REQUIRED es un ámbito de transacción lógica para cada método al que se aplica. Cada uno de estos ámbitos de transacción lógica puede decidir individualmente el estado de solo reversión, con un ámbito de transacción externo que sea lógicamente independiente del ámbito de transacción interno. Por supuesto, en el caso de un comportamiento estándar de PROPAGATION_REQUIRED, se asignarán a la misma transacción física. Por lo tanto, un marcador de solo reversión establecido en el ámbito de la transacción interna afecta la posibilidad de que la transacción externa se confirme. Sin embargo, dado que el alcance de la transacción externa no se decidió por una reversión, la reversión (activada silenciosamente por el alcance de la transacción interna) es inesperada en ese nivel, por lo que se produce una excepción UnexpectedRollbackException.

PROPAGATION_REQUIRES_NEW, en contraste, utiliza una transacción completamente independiente para cada ámbito de transacción afectado. En ese caso, las transacciones físicas subyacentes serán diferentes y, por lo tanto, pueden comprometerse o retrotraerse independientemente, con una transacción externa que no se ve afectada por el estado de reversión de una transacción interna.

PROPAGATION_NESTED es diferente de nuevo en que usa una sola transacción física con múltiples puntos de salvado a los que puede revertir. Estas reversiones parciales permiten que el alcance de una transacción interna desencadene una reversión para su alcance, y que la transacción externa pueda continuar la transacción física a pesar de que algunas operaciones se hayan retrotraído. Por lo general, esto se asigna a los puntos de almacenamiento JDBC, por lo que solo funcionará con las transacciones de recursos JDBC (DataSourceTransactionManager de Spring).

Para completar la discusión: UnexpectedRollbackException también se puede lanzar sin que la aplicación haya establecido un marcador de solo retroceso. 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 actual de la transacción. Esto es particularmente relevante con las transacciones XA.

Como sugerí anteriormente, lanzar una excepción en el ámbito de la transacción interna, luego capturar esa excepción en el ámbito externo y traducirla en una llamada silenciosa de setRollbackOnly debería funcionar para su escenario. Un llamante de la transacción externa nunca verá una excepción en ese momento. Ya que solo se preocupa por tales reversiones silenciosas debido a los requisitos especiales impuestos por la persona que llama, incluso diría que la solución arquitectónica correcta es utilizar excepciones dentro de la capa de servicio y traducir esas excepciones en reversiones silenciosas en el nivel de fachada de servicio (a la derecha). antes de volver a esa llamada especial).

Debido a que su problema posiblemente no solo se trata de excepciones de reversión, sino de excepciones lanzadas desde su capa de servicio, incluso podría usar reversiones estándar impulsadas por excepciones en toda su capa de servicio, y luego capturar y registrar dichas excepciones una vez que la transacción haya ya completado, en alguna fachada de servicio adaptable que traduce las excepciones de la capa de servicio en estados de error específicos de la UI.

Juergen