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

Hibernate Java Discussion :

Problème de cache


Sujet :

Hibernate Java

  1. #1
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut Problème de cache
    Bonjour,

    je développe une application J2EE utilisant entre autres Spring et Hibernate.

    Mon problème est le suivant :

    Si je lance l'application web, puis que je modifie une donnée en base de données, non pas avec Hibernate mais directement en ligne de commande en utilisant une transaction, mon application web ne prend pas en compte le changement.

    Elle affiche toujours l'ancienne valeur.

    J'imagine que ça doit être un problème de cache, mais je ne vois pas comment régler le problème...

    J'ai essayer de faire un refresh sur mon objet Hibernate, voire même de faire un flush ou un clear sur la session courante, mais rien n'y fait ...

    Est ce que quelqu'un a une idée ?

    Je vous remercie par avance.

  2. #2
    Membre éclairé Avatar de eldran64
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2008
    Messages
    344
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2008
    Messages : 344
    Par défaut
    Bonjour,

    Je vois 2 solutions:

    1: débrouilles-toi pour passer par la couche de persistence quoi qu'il arrive.
    2: demandes à hibernate de récupérer toutes les données (cible toutes les tables).

    Voilà, j'espère que je ne t'aurai pas plus embrouiller.

    PS: la première solution me semble la plus correcte.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2009
    Messages
    82
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2009
    Messages : 82
    Par défaut
    Salut,

    Si c'est un problème de cache, alors enlève le cache et voit ce que ça donne sans le cache

    Ps: mets nous un peu ton code qui peut poser problème afin qu'on aide si on peut

  4. #4
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    si t'as activé le cache de second niveau dans hibernate, il gardera en mémoire les objet deshydratés pour ne pas réinterroger la base de donnée. Seule solution viable, désactiver ce cache si tu dois absolument resynchroniser avec la DB.

    si tu utilise une seule session, elle a son propre cache qui va te poser problème. Pour lui, soit tu prend un objet précisément que tu veux "mettre" à jour et tu fait un merge dessus pour recharger les données en DB, soit, plus simple, tu fait un session.close et tu crée une nouvelle session

  5. #5
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    Bonjour,

    j'utilise également une application Java lourd pour administrer mon application, et là aussi j'ai des problèmes de cache !

    J'ai un onglet utilisateur qui permet de modifier les données d'un utilisateur. En cliquant sur nom dans une liste, les informations de cet utilisateur s'affichent. Si je modifie ces données, je fais des set sur cet objet puis je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Session sessionProd = HibernateUtil.getSessionProd();
    Transaction transactionProd = sessionProd.beginTransaction();
    	try {
    		sessionProd.update(accountProd);
    		transactionProd.commit();
    		} catch (HibernateException e) {
    			transactionProd.rollback();
    			throw e;
    		}
    Si je regarde avec un logiciel tel que MySQLQueryBrowser, la modification s'est effectuée correctement.

    Par contre, si j'affiche les informations d'une autre personne, puis que je reviens sur la personne dont j'ai modifié les informations, l'application m'affiche les anciennes infos ! Ce n'est qu'en fermant l'application puis en la réouvrant que j'ai les bonnes informations qui s'affichent ... Donc clairement un problème de cache.

    Voici mon fichier de configuration Hibernate :

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    <!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
     
    <hibernate-configuration>
     
    	<session-factory>
     
    		<!-- Database connection settings -->
    		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    		<property name="connection.url">****</property>
    		<property name="connection.username">****</property>
    		<property name="connection.password">****</property>
     
    		<!-- JDBC connection pool (use the built-in) -->
    		<property name="connection.pool_size">100</property>
     
    		<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    		<property name="hibernate.cache.use_second_level_cache">false</property>
    		<property name="hibernate.jdbc.batch_size">20</property>
     
    		<property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>
     
    		<!-- SQL dialect -->
    		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
     
    		<!-- Echo all executed SQL to stdout -->
    		<property name="show_sql">true</property>
     
    		<!-- UTF-8 -->
     
    		<property name="hibernate.connection.useUnicode">true</property>
    		<property name="hibernate.connection.characterEncoding">utf-8</property>
     
    		<!-- Mapping -->
     
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Account" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Category" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Configuration" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Content" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.ContentSequence" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Field" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.GeographicalZone" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Language" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Level" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.NewsValidation" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Order" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Product" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.Site" />
    		<mapping class="com.cnes.venus.vpds.admin.database.objects.WebPage" />
     
    	</session-factory>
    </hibernate-configuration>
    Comme vous pouvez le voir, j'utilise les annotations.
    J'ai également ajouté l'annotation "@Cache(usage=CacheConcurrencyStrategy.NONE)" dans le Pojo Hibernate Account.

    Pour info, j'utilise des Criteria pour récupérer un Account :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public Account getAccountProd(String login){
    		Session session = HibernateUtil.getSessionProd();
    		Account account = (Account) session.createCriteria(Account.class).setCacheable(false).add(
    				Restrictions.eq("login", login)).setCacheMode(CacheMode.IGNORE).uniqueResult();
    		return account;
    	}
    La encore, j'ai essayé par tous les moyens de désactiver le cache, rien n'y fait...Je ne comprends vraiment pas !

    Merci

  6. #6
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    il y a un cache inhérant à la session hibernate, cache qui n'est pas désactivable pour tout un tas de raisons techniques et qui est spécifique à chaque session. Donc si un client lour sauve des informations modifiées, puis les réaffiche et a les ancienne, c'est la faute au client pas à hibernate, car au sein d'une seul application, il gère ses caches de manière cohérente. En l'occurence, je suppose que soit, pour afficher les données, tu ne fait pas de session.get mais tu récupère des vieilles données ailleurs dans ton application, soit tu utilise deux sessions différentes, donc une n'a pas été fermée après la mise à jour.


    ainsi, ce code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    session1 = .....
    session2 = .....
    Personne p1 = session1.get(Personne.class,id);
    Personne p2 = session2.get(Personne.class,id);
    p2.setNom(p2.getNom()+"blabla");
    session2.saveOrUpdate(p2);
    p1 = session1.get(Personne.class,id);
    // p1 a toujours les anciennes valeurs car mis en cache dans session1 avant la modification
    session1.close();
    session1 = .....
    p1 = session1.get(Personne.class,id);
    // p1 a maintenant les nouvelles valeurs

  7. #7
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    Rien à faire, j'ai beau fermer la session puis la réouvrir par la suite, et utilise une méthode get pour afficher les valeurs de l'objet, les valeurs ne changent pas !

    Est ce que le problème ne viendrait pas de MySQL par hasard ?

  8. #8
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    on peux voir un bout de code qui reproduit le problème? ainsi que la sortie de hibernate (show sql) qui correspond à son exécution.

  9. #9
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    J'ai peut être trouvé une solution, mais ça me parait très lourd ...

    J'ai testé de rajouter le code suivant à deux endroits :

    Account a = (Account)session.get(Account.class, 1);
    System.out.println("AVANT FERMETURE"+a.getFirstName());

    HibernateUtil.closeSessionProd();
    session = HibernateUtil.getSessionProd();
    Account a1 = (Account)session.get(Account.class, 1);
    System.out.println("APRES FERMETURE"+a1.getFirstName());

    =========================

    sur la méthode Update d'un compte :

    La sortie m'affiche les bonnes valeurs, mais l'application Java m'affiche toujours les anciennes valeurs

    =========================

    sur la méthode getAccountProd(String login) :

    La sortie m'affiche les bonnes valeurs ET l'application Java également.

    Je ne comprends pas très bien le problème ... Je ne vais quand même pas fermer et ouvrir la session pour chaque accès à un compte, c'est très peu performant de faire cela non ?

  10. #10
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 276
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 276
    Par défaut
    La session est censée avoir une durée de vie courte.
    La plupart du temps, on doit récupérer une session, démarrer une transaction, faire ses traitements, commiter ou rollbacker et fermer la session.
    Regarde aussi les sessions contextuelles dans la documentation.
    Tout ça devrait régler ton problème.

  11. #11
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    c'est toujours pas clair.

    D'abord, tu utilise un seule session globale pour tout faire? Ou tu utilise une session pour l'interface et une session séparée pour ton update?

    N'oublie pas non plus que hibernate peut faire un close automatique d'une session après un appel à commit(), ce qui implique que HibernateUtil te retournera une nouvelle session. Tout dépend de ta configuration pour ça. De plus, si ton interface garde des référence à tes objet Hibernante, créé avec la session qui est maintenant desynchrone, il vont continuer à utiliser ces vieux objets.

  12. #12
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    J'utilise effectivement une session globale. Je pensais qu'il n'était pas nécessaire de fermer/ouvrir la session pour chaque accès à un objet.

    Même si je ne pense pas que cela va résoudre le problème, comment fait-on pour fermer une session automatiquement après un commit ? Car même si je le fais manuellement, cela ne change rien ...

  13. #13
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    hibernate le fait automatiquement, et je suppose que c'est là ton problème. Tu pense utiliser une seul session, mais tu en as plusieurs. Avec une seule session globale, ce problème n'arriverais pas, car tous le monde utiliserais les même référence d'objet.

  14. #14
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    Dans ce cas là, comment faire pour n'utiliser qu'une seule session globale?

    Je pensais que la classe HibernateUtils permettait de faire cela ...

  15. #15
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    d'abord, de quel hibernateutil on parle? Parceque si il est lié à SessionFactory.currentSession, alors il sera lié aux commits.

  16. #16
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    Voici le code de mon HibernateUtils :

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    public class HibernateUtil {
     
    	private static final SessionFactory sessionFactoryProd;
     
    	static {
    		try {
     
    			URL configFileURL1 = HibernateUtil.class
    					.getResource("hibernateProd.cfg.xml");
    			sessionFactoryProd = new AnnotationConfiguration().configure(configFileURL1)
    					.buildSessionFactory();
     
     
    		} catch (HibernateException ex) {
    			throw new RuntimeException("Exception building SessionFactory: "
    					+ ex.getMessage(), ex);
    		}
    	}
     
    	public static final ThreadLocal sessionProd = new ThreadLocal();
     
    	public static Session getSessionProd() throws HibernateException {
    		Session s = (Session) sessionProd.get();
    		// Open a new Session, if this Thread has none yet
    		if (s == null) {
    			System.out.println("Ouverture de session");
    			s = sessionFactoryProd.openSession();
    			sessionProd.set(s);
    		}
    		return s;
    	}
     
    	public static void closeSessionProd() throws HibernateException {
    		Session s = (Session) sessionProd.get();
    		sessionProd.set(null);
    		if (s != null) {
    			s.close();
    		}
    	}
     
    }

  17. #17
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    ton code n'utilise pas une session, mais une session par Thread. C'est probablement de là que viennent tes erreurs, il y a plusieurs sessions. Difficile d'en faire le compte, ca dépend de ta gestion des Threads. (Utilisation de swing worker, utilisation de "invoke later", etc). Par contre les session ne sont probablement pas automatiquement fermées au commit.

    Le mieux serait que tu notifie, après changement des données, ton interface graphique pour qu'elle relise les données de la db. (session.close() puis refaire des get)

  18. #18
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    Ok, j'ai changé ma classe Hibernate Utils comme ceci :

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    package utils;
     
    import java.net.URL;
     
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.AnnotationConfiguration;
     
    public class HibernateUtil {
     
    	private static final SessionFactory sessionFactoryProd;
     
    	static {
    		try {
     
    			URL configFileURL1 = HibernateUtil.class
    					.getResource("hibernateProd.cfg.xml");
    			sessionFactoryProd = new AnnotationConfiguration().configure(configFileURL1)
    					.buildSessionFactory();
     
    		} catch (HibernateException ex) {
    			throw new RuntimeException("Exception building SessionFactory: "
    					+ ex.getMessage(), ex);
    		}
    	}
     
    	private static Session sessionProd;
     
    	public static Session getSessionProd() throws HibernateException{
    		if(sessionProd == null){
    			System.out.println("Ouverture de session prod");
    			sessionProd = sessionFactoryProd.openSession();
    		}
    		return sessionProd;
    	}
     
    	public static void closeSessionProd() throws HibernateException {
    		if (sessionProd != null) {
    			System.out.println("Fermeture de session prod");
    			sessionProd.close();
    		}
    	}
    }

    Je n'ai plus de problème désormais ... Le problème venait effectivement du fait que j'utilisais des Thread pour les sessions.

  19. #19
    Membre du Club
    Inscrit en
    Avril 2010
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Avril 2010
    Messages : 10
    Par défaut
    J'avais récupérer le code de la classe HibernateUtils sur internet, j'aimerais savoir quel est l'intérêt d'utiliser des Thread pour la gestion des Sessions car si des données ont été modifiées, je ne vois pas bien comment afficher les bons résultats.

    Merci

  20. #20
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    un session hibernante ne peux pas être accédée depuis plusieurs thread différents, elle n'est pas prévues pour et si tu fais ca, attends toi à des erreurs obscure de derrière els fagots, des données corrompues, etc.


    C'est pour ça qu'on fait plusieurs Session. Il n'y a aucun problème à gérer plusieurs sessions en même temps, il faut jsute le faire correctement. C'est pour ça qu'on considère qu'une session doit avoir la durée de vie la plus courte possible (on récupère les donnée, on fait sa popotte dessus, on commit, on close)

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. problème de cache lors du chargement d'applet
    Par ellocin dans le forum Applets
    Réponses: 4
    Dernier message: 05/04/2007, 12h31
  2. [Tomcat 5.5.16] Problème de cache
    Par vallica dans le forum Tomcat et TomEE
    Réponses: 3
    Dernier message: 29/05/2006, 14h59
  3. Problème Mémoire Cache
    Par Ryadus dans le forum Ordinateurs
    Réponses: 6
    Dernier message: 13/12/2005, 16h21
  4. Problème de cache avec Oracle 8i
    Par lper dans le forum Bases de données
    Réponses: 3
    Dernier message: 08/11/2004, 16h50
  5. Problème de cache avec oracle 8 i
    Par lper dans le forum Oracle
    Réponses: 11
    Dernier message: 08/11/2004, 16h45

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