126 votes

Transaction marquée comme rollback uniquement : Comment puis-je trouver la cause

Je rencontre des problèmes pour valider une transaction dans ma méthode @Transactional :

methodA() {
    methodB()
}

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

Lorsque j'appelle methodB() depuis methodA(), la méthode réussit et je peux voir "OK" dans mes logs. Mais ensuite, je reçois

Impossible de valider la transaction JPA ; l'exception imbriquée est javax.persistence.RollbackException : Transaction marquée comme rollbackOnly org.springframework.transaction.TransactionSystemException: Impossible de valider la transaction JPA ; l'exception imbriquée est javax.persistence.RollbackException: Transaction marquée comme 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. Le contexte de methodB est complètement absent dans l'exception - ce qui est normal je suppose ?
  2. Quelque chose à l'intérieur de methodB() a marqué la transaction comme étant en mode rollback uniquement ? Comment puis-je le découvrir ? Y a-t-il par exemple un moyen de vérifier quelque chose comme getCurrentTransaction().isRollbackOnly()? - de cette manière je pourrais parcourir la méthode et trouver la cause.

124voto

Ean V Points 3578

Lorsque vous marquez votre méthode comme @Transactional, l'occurrence de n'importe quelle exception à l'intérieur de votre méthode marquera la TX environnante comme roll-back uniquement (même si vous les attrapez). Vous pouvez utiliser d'autres attributs de l'annotation @Transactional pour l'empêcher de rollback comme:

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

86voto

Vojtěch Points 873

J'ai enfin compris le problème :

methodA() {
    methodB()
}

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

@Transactional
methodC() {
    throw new ...();
}

Ce qui se passe, c'est que même si la methodB a la bonne annotation, la methodC ne l'a pas. Lorsque l'exception est lancée, le deuxième @Transactional marque de toute façon la première transaction comme Rollback only.

54voto

FelixJongleur42 Points 70

Pour récupérer rapidement l'exception causale sans avoir besoin de recoder ou reconstruire, définissez un point d'arrêt sur

org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, ou
org.hibernate.jpa.internal.TransactionImpl() // à partir de Hibernate 4.3

et remontez dans la pile, généralement jusqu'à un intercepteur. Vous pouvez alors lire l'exception causale depuis un bloc catch.

13voto

Kumaresan Perumal Points 1035

J'ai eu du mal avec cette exception en exécutant mon application.

Finalement le problème était dans la requête SQL. Je veux dire que la requête est erronée.

Veuillez vérifier votre requête. C'est ma suggestion

8voto

Mareen Points 405

Recherchez les exceptions qui sont lancées et capturées dans les sections ... de votre code. Les exceptions de l'application en cours d'exécution et de l'annulation des transactions sont annulées lorsqu'elles sont lancées en dehors d'une méthode métier, même si elles sont capturées ailleurs.

Vous pouvez utiliser le contexte pour savoir si la transaction est marquée pour annulation.

@Resource
private SessionContext context;

context.getRollbackOnly();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X