J'ai des problèmes avec la validation d'une transaction dans ma méthode @Transactional:
methodA() {
methodB()
}
@Transactional
methodB() {
...
em.persist();
...
em.flush();
log("OK");
}
Lorsque j'appelle methodB () à partir de methodA (), la méthode passe avec succès et je peux voir "OK" dans mes journaux. Mais alors je reçois
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()...
getCurrentTransaction().isRollbackOnly()?
- comme ceci, je pourrais parcourir la méthode et en trouver la cause.J'ai finalement compris le problème:
methodA() {
methodB()
}
@Transactional(noRollbackFor = Exception.class)
methodB() {
...
try {
methodC()
} catch (...) {...}
log("OK");
}
@Transactional
methodC() {
throw new ...();
}
Qu'est-ce qui se passe, c'est que même si le methodB
a la bonne annotation, le methodC
ne l'a pas. Lorsque l'exception est levée, le second @Transactional
marque la première transaction en tant que restauration uniquement.
Lorsque vous marquez votre méthode comme @Transactional
, l'occurrence d'une exception à l'intérieur de votre méthode marquera le TX environnant comme une restauration uniquement (même si vous les interceptez). Vous pouvez utiliser d'autres attributs de l'annotation @Transactional
pour l'empêcher de revenir en arrière, comme ceci:
@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
Pour récupérer rapidement l’exception responsable sans avoir besoin de re-coder ou de reconstruire, définissez un point d'arrêt sur
org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3
et monter dans la pile, généralement à un certain Interceptor. Là, vous pouvez lire l'exception causante de certains bloc catch.
J'ai eu du mal avec cette exception lors de l'exécution de mon application.
Enfin le problème était lié à la requête SQL . Je veux dire que la requête est fausse.
veuillez vérifier votre requête. C'est ma suggestion
Recherchez les exceptions levées et interceptées dans les sections ...
de votre code. Les exceptions d'application à l'exécution et à l'annulation entraînent une annulation lorsqu'elles sont supprimées d'une méthode métier, même si elles sont interceptées ailleurs.
Vous pouvez utiliser le contexte pour savoir si la transaction est marquée pour une annulation.
@Resource
private SessionContext context;
context.getRollbackOnly();
désactiver le transactionmanager dans votre Bean.xml
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
commentez ces lignes et vous verrez l'exception à l'origine de la restauration;)
J'ai trouvé une bonne explication aux solutions: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
1) supprimez le @Transacional de la méthode imbriquée si elle ne nécessite pas vraiment de contrôle de transaction. Donc, même si elle a une exception, elle ne fait que bouillonner et n’affecte pas les transactions.
OU:
2) si la méthode imbriquée a besoin du contrôle de la transaction, définissez-la comme REQUIRE_NEW pour la stratégie de propagation de cette manière, même si une exception est levée et marquée comme annulation uniquement, l'appelant ne sera pas affecté.
appliquer le code ci-dessous dans productRepository
@Query("update Product set prodName=:name where prodId=:id ") @Transactional @Modifying int updateMyData(@Param("name")String name, @Param("id") Integer id);
pendant que le test junit s'applique sous le code
@Test
public void updateData()
{
int i=productRepository.updateMyData("Iphone",102);
System.out.println("successfully updated ... ");
assertTrue(i!=0);
}
ça fonctionne bien pour mon code
veuillez vérifier votre @ Transactional importez-le.
import javax.transaction.Transactional;