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 :

[Transaction] @Transactional - le rollback ne fonctionne pas [Data]


Sujet :

Spring Java

  1. #1
    Rédacteur
    Avatar de romaintaz
    Homme Profil pro
    Java craftsman
    Inscrit en
    Juillet 2005
    Messages
    3 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Java craftsman
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2005
    Messages : 3 790
    Points : 7 275
    Points
    7 275
    Par défaut [Transaction] @Transactional - le rollback ne fonctionne pas
    Bonjour à toutes et à tous,

    Voilà, j'aimerais faire des tests sur ma BD, et j'aimerais qu'à la fin d'une transaction, toutes mes modifications soient rollbackées.

    Pour ce faire, j'ai un DAO qui est comme suit (il s'agit de l'implémentation DaoImpl, j'ai bien une interface Dao):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class BatchDaoImpl implements BatchDao {
        ...
     
        @Transactional
        public void testTransaction() {
            int nb = jdbcTemplate.update("insert into ...");
            System.out.println("Number of transaction : " + nb);
        }
    }
    Dans mon service :

    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
    public class UpdateDataImpl implements UpdateData {
     
        private BatchDao dao;
     
        public void process() {
            System.out.println("STARTING...");
            try {
                testTransaction();
            } catch (RuntimeException re) {
                System.out.println("Catching Rollback...");
            }
            System.out.println("ENDING.....");
        }
     
        @Transactional
        public void testTransaction() {
            try {
                dao.testTransaction();
            } catch (Exception e) {
                e.printStackTrace();
            }
            throw new RuntimeException("Rollbacking...");
        }
     
        ...
    }
    Ma configuration Spring data-source.xml :

    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
     
    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
            <property name="url" value="..."/>
            <property name="username" value="..."/>
            <property name="password" value="..."/>
        </bean>
     
        <bean id="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             <property name="dataSource" ref="dataSource"/>
          </bean>
     
        <tx:annotation-driven transaction-manager="jdbcTransactionManager"/>
    </beans>
    Et mon applicationContext :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?xml version="1.0" encoding="UTF-8"?>
    <beans ...>
     
        <import resource="data-source.xml"/>
     
        <bean id="batchDao" class="mon.appli.dao.BatchDaoImpl">
            <property name="dataSource" ref="dataSource"/>
        </bean>
     
        <bean id="updateData" class="mon.appli.process.UpdateDataImpl">
            <property name="dao" ref="batchDao"/>
        </bean>
    </beans>
    Tout cela me semble correct, pourtant si j'exécute mon application (qui basiquement va lancer BatchDaoImpl.process()), j'ai les logs suivants :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    STARTING...
    Number of transaction : 1
    Catching Rollback...
    ENDING.....
    Le souci, c'est que l'enregistrement est bien conservé dans ma base de données...

    A noter que si j'enlève @Transactional à la méthode testTransaction du DAO, mon problème persiste.
    Mais si je mets @Transactional(propagation = Propagation.MANDATORY) sur cette même méthode, il me fait une erreur (org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory') ce qui me pousse à penser que la transaction au niveau du service (UpdateDataImpl) n'est pas créée !

    Ma question est donc : qu'ai-je oublié pour activer la transaction ?

    Merci !

    Edit : J'utilise Spring 2.0.6

  2. #2
    Rédacteur
    Avatar de romaintaz
    Homme Profil pro
    Java craftsman
    Inscrit en
    Juillet 2005
    Messages
    3 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Java craftsman
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2005
    Messages : 3 790
    Points : 7 275
    Points
    7 275
    Par défaut
    Visiblement si je fais ce code là dans mon UpdateDataImpl :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        @Transactional
        public void process() {
            System.out.println("STARTING...");
            testTransaction();
            System.out.println("ENDING.....");
        }
    (je vire le try catch, et je mets le @Transactional sur la méthode process), la transaction est bien rollbackée à la fin, mais j'ai la stacktrace du RuntimeException qui est affichée dans les logs, et en plus je fais une transaction sur l'ensemble de la méthode process, alors que je souhaiterais ne la faire que sur testTransaction()...

    Comment faire ?

  3. #3
    Rédacteur
    Avatar de Hikage
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 177
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 177
    Points : 6 301
    Points
    6 301
    Par défaut
    Pour informatiom, le problème dans
    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
     
    public class UpdateDataImpl implements UpdateData {
     
        private BatchDao dao;
     
        public void process() {
            System.out.println("STARTING...");
            try {
                testTransaction();
            } catch (RuntimeException re) {
                System.out.println("Catching Rollback...");
            }
            System.out.println("ENDING.....");
        }
     
        @Transactional
        public void testTransaction() {
            try {
                dao.testTransaction();
            } catch (Exception e) {
                e.printStackTrace();
            }
            throw new RuntimeException("Rollbacking...");
        }
     
        ...
    }
    se situe à l'appel de testTransaction();


    Pour la gestion des transactions, Spring créer un proxy. Lorsqu'une methode du service est appelée par une autre composant ( dans lequel le service à été injecté ), l'appel passe par le proxy qui va ouvrir la transaction, faire l'appel à ta methode, et au retour gérer la fin de transaction.

    Or ici, testTransaction(), qui est ta methode transactionnelle est appelée directement dans le service, et donc tu ne passe pas dans le proxy.
    Résultat, la transaction n'est pas gérée par Spring.

  4. #4
    Rédacteur
    Avatar de romaintaz
    Homme Profil pro
    Java craftsman
    Inscrit en
    Juillet 2005
    Messages
    3 790
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Java craftsman
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2005
    Messages : 3 790
    Points : 7 275
    Points
    7 275
    Par défaut
    Hikage, c'est effectivement ça

    Merci !

  5. #5
    Nouveau membre du Club Avatar de Hyperion99
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    62
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 62
    Points : 35
    Points
    35
    Par défaut
    Bonjour à tous,

    Débutant avec Spring et hibernate , j'aurai quelques précision à vous demander :

    voici ma classe service

    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
    @Service("faxServiceTarget")
    @Scope("singleton")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public class FaxService implements IFaxService {
     
      public IFaxModel saveFaxModel(IFaxModel faxModel) {
            return getFaxDao().saveFaxModel(faxModel);
        }
     
         public IFaxModel monTest(IFaxModel faxModel) throws Exception {
            faxModel = saveFaxModel(faxModel);
            if (true) {
                throw new Exception("montest esception");
            }
            return faxModel;
        }
    }

    mon test :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     @Test
          public void saveFaxModel2() {
              IFaxModel faxModel_1 = (IFaxModel) getXmlBeanFactory().getBean("faxModel_1");
            try {
                faxModel_1 = getFaxService().monTest(faxModel_1);
            } catch (Exception e) {
                e.printStackTrace();  
            }
            assert faxModel_1 != null && faxModel_1.getId() != null && faxModel_1.getFaxResults() != null;
          }
    Je ne sais pas si j'ai bien fait mais j'ai la notion de transaction au niveau de ma classe et non au niveau des méthodes (c'est peut être de la que vient mon problème ? d'ailleurs quels sont les avantages et inconvénients d'un tel choix )

    Ce que je ne comprend pas c'est pourquoi la sauvegarde de mon object est bien faite en base

    Hikage nous dit :

    Pour la gestion des transactions, Spring créer un proxy. Lorsqu'une methode du service est appelée par une autre composant ( dans lequel le service à été injecté ), l'appel passe par le proxy qui va ouvrir la transaction, faire l'appel à ta methode, et au retour gérer la fin de transaction.

    Or ici, testTransaction(), qui est ta methode transactionnelle est appelée directement dans le service, et donc tu ne passe pas dans le proxy.
    Résultat, la transaction n'est pas gérée par Spring.
    Mon problème proviendrait il du faite que mon save et ma génération de l'exception dans mon service sont faite dans deux transactions différentes vu que j'appelle saveFaxModel depuis mon service et non directement depuis mon test ?

    Si c'est le cas comment faire pour que les opérations faites durant un enchaînement de méthodes du même service soient atomique, c'est à dire que si une des méthodes lève une exception, les méthode précédemment exécutées soient "RollBacké"

    Merci d'avance pour votre aide
    ++

  6. #6
    Nouveau membre du Club Avatar de Hyperion99
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    62
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 62
    Points : 35
    Points
    35
    Par défaut
    au cas ou cela aurait son importance je mets aussi le code qui sauvegarde en base mon objet

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     
        public IFaxModel saveFaxModel(IFaxModel faxModel) {
            HibernateTemplate ht = getHibernateTemplate();
            ht.saveOrUpdate(faxModel);
            return faxModel.getId();
        }

  7. #7
    Nouveau membre du Club Avatar de Hyperion99
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    62
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mai 2006
    Messages : 62
    Points : 35
    Points
    35
    Par défaut
    bon en faite je pense avoir trouvé ma réponse .... sur ce forum , j'aurai du chercher encore plus avant de poster , mille excuse

    La réponse est fourni par willoi

    sur le poste suivant http://www.developpez.net/forums/d51...e-fonctionner/


    Si je change ma classe service :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    @Service("faxServiceTarget")
    @Scope("singleton")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED ) 
    public class FaxService implements IFaxService {
    [...]
    }
    en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    @Service("faxServiceTarget")
    @Scope("singleton")
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED , rollbackFor = Exception.class)
    public class FaxService implements IFaxService {
    [...]
    }
    La sauvegarde de mon objet ne se fait pas en base....

    Quand même , au cas où..., si quelqu'un peut me confirmer que c'est la bonne manière de faire ...

    Merci d'avance , et encore désolé de ne pas avoir assez chercher ...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Data] [HIBERNATE] Le rollback ne fonctionne pas
    Par verbose dans le forum Spring
    Réponses: 3
    Dernier message: 24/04/2014, 23h48
  2. Access 2000 BeginTrans/Rollback ne fonctionne pas
    Par olivier] dans le forum VBA Access
    Réponses: 1
    Dernier message: 01/02/2013, 17h24
  3. Rollback ne fonctionne pas
    Par <% Bastien %> dans le forum JPA
    Réponses: 1
    Dernier message: 31/08/2011, 12h04
  4. les dernières requêtes d'une transaction ne fonctionne pas
    Par pimos dans le forum Windows Forms
    Réponses: 1
    Dernier message: 27/05/2009, 15h24
  5. BEGIN TRANSACTION ne fonctionne pas (webapp et pool)
    Par ouragan44 dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 12/04/2006, 11h30

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