Transacción marcada como retroceder solamente: ¿Cómo puedo encontrar la causa?

Tengo problemas para realizar una transacción con mi método @Transactional:

methodA() { methodB() } @Transactional methodB() { ... em.persist(); ... em.flush(); log("OK"); } 

Cuando llamo a methodB () desde methodA (), el método se ejecuta satisfactoriamente y puedo ver “OK” en mis registros. Pero luego me sale

 Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) at methodA()... 
  1. El contexto del método B falta por completo en la excepción, ¿está bien, supongo?
  2. Algo dentro del métodoB () marcó la transacción como rollback solamente? ¿Cómo puedo averiguarlo? ¿Hay, por ejemplo, una forma de comprobar algo como getCurrentTransaction().isRollbackOnly()? – así podría pasar por el método y encontrar la causa.

Cuando marque su método como @Transactional , la aparición de cualquier excepción dentro de su método marcará el TX circundante como retroceso solamente (incluso si los detecta). Puede usar otros atributos de la anotación @Transactional para evitar que retroceda como:

 @Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class) 

Finalmente entendí el problema:

 methodA() { methodB() } @Transactional(noRollbackFor = Exception.class) methodB() { ... try { methodC() } catch (...) {...} log("OK"); } @Transactional methodC() { throw new ...(); } 

Lo que ocurre es que, aunque el methodB tiene la anotación correcta, el methodC no. Cuando se lanza la excepción, el segundo @Transactional marca la primera transacción como Rollback solo de todos modos.

Para obtener rápidamente la excepción causante sin la necesidad de volver a codificar o reconstruir , configure un punto de interrupción en

 org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3 

y sube a la stack, generalmente a algún Interceptor. Allí puede leer la excepción causante de algún bloque catch.

Luché con esta excepción al ejecutar mi aplicación.

Finalmente, el problema estaba en la consulta SQL . quiero decir que la consulta es incorrecta.

por favor verifica tu consulta. Esta es mi sugerencia

Busque las excepciones lanzadas y atrapadas en las ... secciones de su código. Las excepciones de la aplicación en tiempo de ejecución y rollback provocan una reversión cuando se descarta un método comercial, incluso si se detecta en otro lugar.

Puede usar el contexto para averiguar si la transacción está marcada para reversión.

 @Resource private SessionContext context; context.getRollbackOnly(); 

deshabilite el administrador de transacciones en su Bean.xml

     

comente estas líneas y verá la excepción que causa la reversión;)

Encontré una buena explicación con las soluciones: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/

1) elimine @Transacional del método nested si realmente no requiere control de transacción. Así que incluso tiene una excepción, simplemente burbujea y no afecta las transacciones.

O:

2) si el método nested necesita control de transacción, hágalo como REQUIRE_NEW para la política de propagación de esa manera, incluso si arroja una excepción y se marca como solo reversión, la persona que llama no se verá afectada.