IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Java Discussion :

TransactionSystemException Vs ConstraintViolationException


Sujet :

Spring Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Par défaut TransactionSystemException Vs ConstraintViolationException
    Bonjour à tous,

    J'ai un petit problème que je ne comprend pas, et pour lequel j'aurais bien aimé un peu d'aide.

    Pour commencer, j'ai un test :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    @SpringApplicationContext("test-applicationContext.xml")
    @DataSet
    public class MonServiceTest extends UnitilsJUnit4 {
     
    	@SpringBeanByName
    	private MonService monService;
     
    	@Test(expected = ConstraintViolationException.class)
    	public void testCreateVide() {
    		final MonBean beanVide = new MonBean();
    		monService.createBean(beanVide);
    	}
     
    	...
    Ce test appelle donc un service (passe plat ici) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    @Service
    public class MonService {
     
    	@Autowired
    	private MonDao monDao;
     
    	public void createBean(MonBean bean) {
    		monDao.createBean(bean);
    	}
     
    	...
    Et donc le DAO, très simple lui aussi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    @Repository
    public class MonDao {
     
    	@PersistenceContext
    	private EntityManager entityManager;
     
    	@Transactional
    	public void createBean(MonBean bean) {
    		entityManager.persist(bean);
    	}
     
    	...
    Le test est conçu pour échouer (d'où le expected) puisque j'utilise un bean vide. Les contraintes sur les champs du bean font que ça doit planter.

    Plus concrètement, si je met un log dans le DAO, comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
    	@Transactional
    	public void createSite(Site newSite) {
     
    		try {
    			entityManager.persist(newSite);
     
    		} catch (RuntimeException e) {
    			System.out.println("***DAO***"+e.getClass());
    			logger.error(e.getMessage(), e);
    			throw e;
    		}
    	}
    J'obtiens bien la trace suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    ***DAO***class javax.validation.ConstraintViolationException
    ERROR: com.moi.MonDao - Validation failed for classes [com.moi.MonBean] during persist time for groups [javax.validation.groups.Default, ]
    List of constraint violations:[
    	ConstraintViolationImpl{interpolatedMessage='ne peut pas être vide', propertyPath=name, rootBeanClass=class com.moi.MonBean, messageTemplate='{org.hibernate.validator.constraints.NotBlank.message}'}
    	ConstraintViolationImpl{interpolatedMessage='Au moins une langue doit être sélectionnées', propertyPath=langs, rootBeanClass=class com.moi.MonBean, messageTemplate='{com.moi.monbean.checklangs}'}
    	ConstraintViolationImpl{interpolatedMessage='ne peut pas être vide', propertyPath=visualId, rootBeanClass=class com.moi.MonBean, messageTemplate='{org.hibernate.validator.constraints.NotBlank.message}'}
    ]
    J'obtiens bien une trace équivalente quand j'ajoute des logs dans le service.

    Par contre, mon test JUnit (lancé depuis Eclipse) est rouge. J'ai une TransactionSystemException alors que je devrais avoir une ConstraintViolationException. Et je ne comprend pas comment/pourquoi la TransactionSystemException arrive...

    J'ai la trace suivante dans JUnit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    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.unitils.database.transaction.impl.DefaultUnitilsTransactionManager.commit(DefaultUnitilsTransactionManager.java:137)
    	at org.unitils.database.DatabaseModule.commitTransaction(DatabaseModule.java:421)
    	at org.unitils.database.DatabaseModule.endTransactionForTestMethod(DatabaseModule.java:396)
    	at org.unitils.database.DatabaseModule$DatabaseTestListener.afterTestTearDown(DatabaseModule.java:540)
    	at org.unitils.core.Unitils$UnitilsTestListener.afterTestTearDown(Unitils.java:315)
    	at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runBeforesThenTestThenAfters(UnitilsJUnit4TestClassRunner.java:159)
    	at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    	at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    	at org.unitils.UnitilsJUnit4TestClassRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:95)
    	at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61)
    	at org.unitils.UnitilsJUnit4TestClassRunner.access$000(UnitilsJUnit4TestClassRunner.java:44)
    	at org.unitils.UnitilsJUnit4TestClassRunner$1.run(UnitilsJUnit4TestClassRunner.java:62)
    	at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    	at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    	at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:68)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
    	at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:73)
    	at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:512)
    	... 23 more
    Si quelqu'un pouvait m’éclairer.

    Merci d'avance.
    Thierry Leriche-Dessirier
    Consultant Java JEE Web Agile freelance
    Rédacteur pour Developpez
    Professeur de Génie Logiciel à l'ESIEA

    Site : http://www.icauda.com / Linked'in : http://www.linkedin.com/in/thierryler / Twitter : @ThierryLeriche

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 124
    Par défaut
    Bonjour,

    De ce que j'en pense :
    - Premièrement mettre le @Transactional sur le DAO plutôt que sur le service ça me parait pas super conceptuellement parlant
    - Deuxièmement, les transactions des tests Junits sont rollBackOnly comme indiqué d'ailleurs dans le message d'erreur. La violation de contrainte, qui devrait se produire au moment du commit, n'intervient donc jamais.

    Essayez de rajouter @TransactionConfiguration(defaultRollback=false) sur votre test.

    Bonne soirée.

  3. #3
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Par défaut
    Bonjour,

    J'ai ajouté @TransactionConfiguration(defaultRollback=false) sur la classe de test mais ça ne change rien. J'ai essayé de le mettre directement sur le test mais Eclipse le refuse.
    Thierry Leriche-Dessirier
    Consultant Java JEE Web Agile freelance
    Rédacteur pour Developpez
    Professeur de Génie Logiciel à l'ESIEA

    Site : http://www.icauda.com / Linked'in : http://www.linkedin.com/in/thierryler / Twitter : @ThierryLeriche

  4. #4
    Membre émérite

    Homme Profil pro
    Architecte technique
    Inscrit en
    Juin 2005
    Messages
    588
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2005
    Messages : 588
    Par défaut
    Bonjour Thierry,

    Au niveau createSite il est normal de tracer ContraintViolationException; ensuite, cette exception est wrappée par Spring sur TransactionSystemException ! Il me semble donc normal qu'au niveau de ton test tu te retrouves avec un TransactionSystemException...

    Ajouter @TransactionConfiguration au niveau de ta classe de test n'apporte rien puisque que tes transactions son traitées au niveau DAO !

    Pour le reste: comme écrit plus haut, une DAO ne devrait pas avoir de méthode annotée @Transactional (i.e. c'est effectivement au niveau du service que les transactions devraient être traitées).

    a+
    Philippe

  5. #5
    Rédacteur
    Avatar de thierryler
    Homme Profil pro
    Inscrit en
    Octobre 2007
    Messages
    4 078
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 078
    Par défaut
    Je suis d'accord sur le fait que ce n'est pas le dao qui fait porter le @Transactional. Je l'ai mis sur mon service :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    @Service
    public class SiteService {
     
    	@Autowired
    	private SiteDao siteDao;
     
    	@Transactional
    	public void createSite(Site newSite) {
    		siteDao.createSite(newSite);
    	}
    ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    @Repository
    public class SiteDaoImpl implements SiteDao {
    	@Override
    	public void createSite(Site newSite) {
    		logger.debug("createSite");
    		entityManager.persist(newSite);
    		logger.info("New site created  [id] {}", newSite.getId());
    	}
    ...
    Mais ça ne change rien quant au résultat de mon test :-(

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    @SpringApplicationContext("test-applicationContext.xml")
    @DataSet
    @TransactionConfiguration(defaultRollback=false)
    public class SiteServiceTest extends UnitilsJUnit4 {
     
    	@SpringBeanByName
    	private SiteService siteService;
     
    	@Test(expected = ConstraintViolationException.class)
    	public void testCreateSite_00() {
    		final Site site = new Site();
    		siteService.createSite(site);
    	}
    ...
    Thierry Leriche-Dessirier
    Consultant Java JEE Web Agile freelance
    Rédacteur pour Developpez
    Professeur de Génie Logiciel à l'ESIEA

    Site : http://www.icauda.com / Linked'in : http://www.linkedin.com/in/thierryler / Twitter : @ThierryLeriche

  6. #6
    Membre émérite

    Homme Profil pro
    Architecte technique
    Inscrit en
    Juin 2005
    Messages
    588
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2005
    Messages : 588
    Par défaut
    Pour moi, le fait que tu reçoives une TransactionSystemException n'est pas si illogique même en positionnant defaultRollBack à false... à voir donc mais je ne suis pas sûr que ce comportement soit documenté...

    Dans mes tests (j'en ai fait une série ce jour) je teste TransactionSystemException, mais effectivement la question mérite réflexion...

  7. #7
    Membre émérite

    Homme Profil pro
    Architecte technique
    Inscrit en
    Juin 2005
    Messages
    588
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2005
    Messages : 588
    Par défaut
    Regardes du côté de la doc de référence

    Perso, je suis en Spring 2.5 et je peux donc utiliser l'annotation @NotTransactional (pour la partie non transactionnelle) et @Rollback(false)... mais dans les test je privilégie une gestion manuelle des transactions... Avantage: pouvoir lancer des commit dans le test lui même.

    Pour info: TransactionSystemException.getApplicationException() te donne l'origine de l'exception.

    J'ai joué avec @Rollback(false) & l'exception TransactionSystemException: bizarrement, si on fournit TransactionSystemException.class comme exception attendue... JUnit n'en veut pas => je m'en retourne donc à une gestion manuelle des transaction pour les tests...

    a+

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 124
    Par défaut
    Bonsoir,

    Ne comprenant pas trop pourquoi tu ne récupères pas vraiment l'erreur 'réelle', j'ai fais le test chez moi pour voir (bon par contre je suis pas sur du hibernate, et c'est probablement la différence).

    Mon test :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "classpath*:spring-services.xml", "/spring-database.xml", "/spring-context.xml" })
    @TransactionConfiguration(defaultRollback=false)
    public class TestViolationConstraint {
     
      @Autowired
      private IServiceEmplacementLit serviceEmplacementLit;
     
      @Test
      public void test() {
        LieuGeo lieu = new LieuGeo();
        lieu.setCodeLieu("TOTO");
        lieu.setTypeLieu("LG");
        lieu.setMaxEml(3);
     
        serviceEmplacementLit.creerListeEml(lieu);
      }
    Mon service :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    @Transactional(value = "txSIPSDM")
    public class ServiceEmplacementLit implements IServiceEmplacementLit {
    [...]
    Là j'essaie d'insérer un enregistrement dont le parent (le couple TOTO / LG) n'existe pas.

    Et j'ai ce résultat dans ma trace Junit du test :

    ERROR 10-05 19:00:57,421 (Logging.java:logException:69) -Erreur dans le service : ServiceEmplacementLit - creerListeEml
    9500 [main] ERROR fr.sib.sillageIdMvt.service.ServiceEmplacementLit - Erreur dans le service : ServiceEmplacementLit - creerListeEml
    ERROR 10-05 19:00:57,421 (Logging.java:logException:70) - Paramètre d'appel (Type - Valeur) :
    9500 [main] ERROR fr.sib.sillageIdMvt.service.ServiceEmplacementLit - Paramètre d'appel (Type - Valeur) :
    ERROR 10-05 19:00:57,421 (Logging.java:logException:73) - class fr.sib.sillageIdMvt.metier.LieuGeo - fr.sib.sillageIdMvt.metier.LieuGeo@4c4f1c6
    9500 [main] ERROR fr.sib.sillageIdMvt.service.ServiceEmplacementLit - class fr.sib.sillageIdMvt.metier.LieuGeo - fr.sib.sillageIdMvt.metier.LieuGeo@4c4f1c6
    ERROR 10-05 19:00:57,421 (Logging.java:logException:75) -PreparedStatementCallback; SQL [INSERT INTO cmp_eml(eml_c_ide, tli_c_cod, lig_c_ide, eml_c_mne, eml_l_lib, eml_l_pro, eml_l_loc, eml_b_dis, eml_d_deb, eml_d_fin) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; ORA-02291: violation de contrainte (SIPSDM.FK1_CMP_EML) d'intégrité - touche parent introuvable
    ; nested exception is java.sql.SQLIntegrityConstraintViolationException: ORA-02291: violation de contrainte (SIPSDM.FK1_CMP_EML) d'intégrité - touche parent introuvable
    Ce qui me parait plutôt pas mal.

    Juste pour info, si tu remontes les getCause() de ton exception TransactionSystemException tu finis pas par retrouver la bonne ? P'tet un enrobage Spring/Hibernate de l'erreur de base ?

    Charles.

Discussions similaires

  1. Réponses: 6
    Dernier message: 24/09/2011, 13h03
  2. ConstraintViolationException non catchée
    Par FunkyBreizh dans le forum Hibernate
    Réponses: 3
    Dernier message: 15/01/2011, 18h22
  3. Réponses: 1
    Dernier message: 20/08/2010, 09h50
  4. JBoss, Hibernate et ConstraintViolationException
    Par romainw dans le forum Hibernate
    Réponses: 3
    Dernier message: 30/01/2009, 11h50
  5. Pb Transaction sur ConstraintViolationException
    Par perezoso dans le forum Hibernate
    Réponses: 1
    Dernier message: 23/08/2007, 13h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo