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 :

[Hibernate] Gestion d'acces concurrents


Sujet :

Hibernate Java

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    370
    Détails du profil
    Informations personnelles :
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Avril 2006
    Messages : 370
    Points : 223
    Points
    223
    Par défaut [Hibernate] Gestion d'acces concurrents
    Pour utiliser ma persistance Hibernate, j'utilise une classe Singleton implementant les différentes methodes d'action sur les objets 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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
     
    public class HibernateManager implements DBAccessManager {
     
    	private static HibernateManager hibernateManager;
    	private Session session ;
     
    	private HibernateManager() {}
     
    	public static synchronized HibernateManager getInstance(){
    		if (hibernateManager == null)
    			hibernateManager = new HibernateManager();
    		return hibernateManager ;
    	} 
     
     
     
    	public void startSession() {
    		session = HibernateUtil.currentSession();
    	}
     
    	public void startTransaction() {
    		try {
    			session.beginTransaction();
    		} catch (HibernateException he){
    			he.printStackTrace();
    		}
    	}
     
    	public void commit() {
    		session.getTransaction().commit();
    	}
     
    	public void rollback() {
    		session.getTransaction().rollback();
    	}
     
    	public void save(Object o) {
    		try {
    			session.saveOrUpdate(o);
    		} catch (HibernateException he) {
    			he.printStackTrace();
    		}	 
    	}
     
    	public void closeSession() {
    		HibernateUtil.closeSession();
            session=null;
    	}
     
    	public void updateSession() {
    		try {
    			session.flush();
    		} catch (HibernateException he) {
    			he.printStackTrace();
    		}	
     
    	}
     
    	public void delete(Object o) {
    		try {
    			session.delete(o);
    		} catch (HibernateException he) {
    			he.printStackTrace();
    		}	 
    	}
     
    	public void deleteCollection(Collection collection) {
    		for(Iterator it=collection.iterator();it.hasNext();){
    			try {
    				session.delete((Object)it.next());
    			} catch (HibernateException he) {
    				he.printStackTrace();
    			}	 
     
            }	
    	}
     
    	public void saveCollection(Collection collection) {
    		for(Iterator it=collection.iterator();it.hasNext();){
    			try {
    				session.saveOrUpdate((Object)it.next());
    			} catch (HibernateException he) {
    				he.printStackTrace();
    			}	 
     
    		}
    	}
     
    	public void attach(Object o) {
    		try {
    			session.refresh(o,LockMode.UPGRADE);
    		} catch (HibernateException he) {
    			he.printStackTrace();
    		}	
     
        }
     
        public void detach(Object o) {
        	try {
        		session.evict(o);
    		} catch (HibernateException he) {
    			he.printStackTrace();
    		}	
     
        }
     
    	public User recupererUser(int id){
    		Session s = HibernateUtil.currentSession();
    		Transaction tx = s.beginTransaction();
     
    		User us = (User) s.get(User.class,id);
     
    		tx.commit();
    		HibernateUtil.closeSession();
    		return us;
    	}
     
    	public Fichier recupererFichier(int idFic){
    		Session s = HibernateUtil.currentSession();
    		Transaction tx = s.beginTransaction();
     
    		Fichier fic = (Fichier) s.get(Fichier.class,idFic);
     
    		tx.commit();
    		HibernateUtil.closeSession();
    		return fic;
     
    	}
     
    	@SuppressWarnings("unchecked")
    	public List getUserList() {
    		Criteria criteria = null;
    		List results = null;
    		try {
    			criteria = session.createCriteria(User.class);
    			results = (java.util.List<User>) criteria.list();
    		} catch (HibernateException he) {
    			he.printStackTrace();
    		}	
    		return results;
    	}
    }
    Lors de l'utilisation de celle-ci, je procède de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
                            manager.startSession();
    			manager.startTransaction();
    			manager.attach(Objet);
    			//action sur objet
    			manager.commit();
                            manager.closeSession();
    Or, cette portion de code se retrouve dans plusieurs methode de plusieurs objet differents avec des actions différentes.
    Travaillant avec Tomcat et des Servlets, ces methodes peuvent être éxécutées simultanéments. Or dans cas, se pose le problème de mon attribut session de mon manager, en effet celui-ci va se retrouvé partagé et si d'un coté une methode appelle le closeSession() et que de l'autre une autre methode est en plein traitement alors elle ne pourra plus travaillé et génèrera une exception.

    Même l'utilisation de bloc synchronize(this), ne résoud pas le problème car il empèchera l'execution concurrente au sein de la même méthode pas pour l'ensemble.

    Voyez vous un moyen de protéger efficacement ce code car moi je sèche ...

    Edit : Voici un morceau de discution privee avec BizuR

    Je vois ce que tu veux dire ... mais il me semble que si le prog est executé plusieurs fois (par différents user), la session Factory est propre à un lancement et non à plusieurs ...

    Par contre, si tu es en Web (donc un seul lancement), à toi de rendre serializable la session (une par user) ou bien carrément la sessionFactory histoire qu'il se demmerde avec après coup et qu'il fasse comme il l'entend.

    Perso, je vois que tu es en sessions courtes... en mode Web, ne serait il pas plus intéressant de caler les session d'Hibernate avec la session Web ?!? Comme ca, a tout nouveau user, tu crées une nouvelle session, et il la garde jusqu'a sa déconnexion ... ca t'évitera, entre autre de couper ta session à chaque opération ... mais bon, après c'est toi qui voit.


    Donc en gros, chaque user possède un attribut transcient de session, qui lui est attribué à la connexion par exemple et chaque operation de chaque user est réalisé à partir de sa session. Donc mes methodes de classe restent les même à l'exception qu'elle prennent en attribut la session de l'utilisateur. J'ai bon ?
    La posix attitude ...

  2. #2
    Membre éclairé Avatar de BizuR
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    688
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 688
    Points : 757
    Points
    757
    Par défaut
    Ce qui va poser problème ici n'est pas ton Hibernate Manager en singleton (puisqu'il constitue un service) mais plutot ton fichier HibernateUtil qui va threader l'execution de l'appli et ne s'arraner que pour conserver qu'une session par execution de l'appli.

    Je pense que c'est a ce niveau (et au niveau des fonctions startSession() et closeSession()) que tu dois intervenir en changeant leur implémentation ... de manière a justement livré plusieurs sessions a chaque fois, ou bien géré une session par utilisateur ... c'est à toi de voir apres

    Comme j'ai dit par contre, je miserai plus sur une synchronisation des sessions Web et Hibernate afin d'éviter certaines complications et d'optimiser, pourquoi pas, l'utilisation d'Hibernate (notamment avec le cache de premier niveau "inclus" dans les sessions )
    See you, space cowboy... and if you're satisfied, click on

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    370
    Détails du profil
    Informations personnelles :
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Avril 2006
    Messages : 370
    Points : 223
    Points
    223
    Par défaut
    Alors je ne doit pas trop comprensre ce que tu entend par synchronisation entre Session web et session Hibernate.

    Ce n'est pas ce que j'ai décrit plus haut ? A savoir que lorsqu'un User se connecte, on lui attribut une session Hiberntae et on stocke le tout dans un Session Java et donc cela est OK pour l'ensemble de sa session sur mon site.

    Oui j'avais remarqué que dans le cas d'une utilisation comme celle-ci je ne doit pas utiliser HibernateUtil, mais simplement avoir une StartSession qui me retourne une session (J'envisage donc plutot que mon manager mossède une Fabrique de Session et ainsi me délivre une session à chaque fois).
    La posix attitude ...

  4. #4
    Membre éclairé Avatar de BizuR
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    688
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 688
    Points : 757
    Points
    757
    Par défaut
    Sisi c'est la même chose ... sinon, perso, tu n'es pas forcé de mettre une sessionfactory dans ton manager... il suffit que tu entretiennes, dans HibernateUtil, une map des utilisateurs connectés et de leur session correspondante (l'id serait l'id du user par exemple ou un ID généré à la première demande ...

    Ainsi, tu refiles l'ID au user (en session) et quand il demande un startSession, tu demandes en paramètre ce fameux ID ... il récuperera alors facilement sa session

    La difficulté sera surtout au niveau de cette map de flusher régulièrement pour vider les session inutiles (d'utilisateurs connectés) et oualah
    See you, space cowboy... and if you're satisfied, click on

  5. #5
    Membre régulier
    Inscrit en
    Octobre 2002
    Messages
    108
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 108
    Points : 98
    Points
    98
    Par défaut
    Ton code ne peut pas fonctionner dans un environnement multithread. Puisque ton HibernateManager qui est à priori singleton, est utilisé par plusieurs thread en même temps. Alors qu'il a un attribut de type Session qui doit être utilisé par une seule thread à la fois. Pour cela, il faut modifier l'implementation de HibernateManager. Je te conseille de consulter la documentation de ThreadLocal et HibernateUtil.

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    370
    Détails du profil
    Informations personnelles :
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Avril 2006
    Messages : 370
    Points : 223
    Points
    223
    Par défaut
    Justement, je me demandais dans une appli web avec Tomcat et Servlet :
    Chaque requète HTTP est traité dans une thread au niveau de Tomcat ca on est d'accord.

    Mais es ce que ce threading est conservé derrière la Servlet, qui plus est dans mon cas il y a un Singleton derrière, et alors les appel de methode métier pour chaque requète ont lieu au sein d'un thread. Ou alors l'application devient elle mono-thread a moins de threader explicitement ?

    Sinon, avec ton idée trungsi, je conserve les sessions courtes c'est bien ca ? Mais BizuR semblai indiquer que dans mon cas, les sessions longues, synchronisé sur la session Web serait avantageux.

    Edit : petite question subsidiaire :

    Vaut t'il mieux stocker en session l'objet User en lui même (et donc remettre un objet à jour dans la session après chaque travail sur celui-ci) ou alors stocker simplement l'id de l'user en session et rechercher dans le code metier l'user correspondant (access base, gestion d'une liste user connécté) ?
    La posix attitude ...

  7. #7
    Membre éclairé Avatar de BizuR
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    688
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 688
    Points : 757
    Points
    757
    Par défaut
    Attention, je ne t'indique rien, je propose des solutions
    Je ne suis pas encore assez expert en la matière pour te dire ce qui sera le mieux ou non. Ce que je trouve dommage avec les sessions courtes, c'est que l'on perd toute la notion de cache (pour le premier niveau). Une session par utilisateur (donc vu que t'es en Servlet, une session par session Web). Maintenant, certaines documentations préconisent une session liée à la transaction ... cela reste un choix stratégique et je ne saurais te dire si l'un ou l'autre est plus ou moins rentable dans la mesure où je n'ai pas encore utilisé hibernate pour ce faire

    Je pourrai mieux te répondre sur l'efficacité d'hibernate selon les paramétrages une fois mon bench terminé pour le boulot (fin juin)
    D'ici la, je ne peux donner autre chose que des avis personnels
    See you, space cowboy... and if you're satisfied, click on

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    370
    Détails du profil
    Informations personnelles :
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Avril 2006
    Messages : 370
    Points : 223
    Points
    223
    Par défaut
    Oui j'ai lu cet article et en effet c'est l'une des choses qui m'avait fait opter pour la session lié à la transaction (mais en même temps je n'est pas compris grand chose des explications qui suivaient).

    Par contre je réfléchi au post de trungsi, et je ne vois pas vraiment comment modifié ma classe HibernateManager. J'ai vu que HibernateUtil avez les sessions en ThreadLocal, donc logiquement la variable session est unique pour chaque thread.
    Mais donc comment faire en sorte que ca le soit aussi au niveau de mon manager (sachant que c'est un singleton).

    Donc si trungsi ou quelqu'un qui "voit" le truc pouvait expliquer avec pourquoi pas du code je suis preneur ...
    La posix attitude ...

  9. #9
    Membre régulier
    Inscrit en
    Octobre 2002
    Messages
    108
    Détails du profil
    Informations forums :
    Inscription : Octobre 2002
    Messages : 108
    Points : 98
    Points
    98
    Par défaut
    1er Refactoring : Tu peux supprimer l'attribut session de HibernateManager et faire appel directement à HibernateUtil.

    Par ex:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public void startTransaction() {
        HibernateUtil.currentSession().startTransaction();
    }
     
    public void commit() {
        HibernateUtil.currentSession().getTransaction().commit();
    }
    ...
    2e refactoring: si HibernateManager ne fait que déléguer les appels à HibernateUtil, tu peux supprimer HibernateManager et utiliser directement HibernateUtil.

    Bon refactoring

  10. #10
    Membre actif
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    370
    Détails du profil
    Informations personnelles :
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Avril 2006
    Messages : 370
    Points : 223
    Points
    223
    Par défaut
    Et en modifiant mon code 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
     
    Session s = null;
    		try {
    			s = manager.startSession();
    			manager.startTransaction(s);
    			manager.attach(us,s);
    			us.removeFichier(f);//On enleve le fichier de la liste des fichiers de l'utilisateur
    			manager.commit(s);
    		}
    			catch (IllegalArgumentException e) {
    				e.printStackTrace(); //Avertir du pb le fichier ne peut être supprimé
    			} catch (HibernateException e) {
    				e.printStackTrace();
    				manager.rollback(s);
    			}
    			finally {
    				manager.closeSession(); //Quoi qu'il arrive, on clos la session
    			}
    avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public Session startSession() {
    		return HibernateUtil.currentSession();
    	}
    alors je reste bien avec une session par transaction, et je suis bien threadsafe grace a la session en threadLocal par hibernateUtil.

    Mon problème est t'il résolu ?
    La posix attitude ...

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

Discussions similaires

  1. Réponses: 9
    Dernier message: 30/04/2008, 09h55
  2. Gestion des accès concurrents sous DELPHI/PARADOX.
    Par tarbala dans le forum Bases de données
    Réponses: 8
    Dernier message: 04/02/2008, 19h13
  3. [Conception] Gestion d'accès concurrent
    Par youcef81 dans le forum Langage
    Réponses: 6
    Dernier message: 23/07/2007, 11h58
  4. Gestion des accès concurrent
    Par nicoaix dans le forum Access
    Réponses: 3
    Dernier message: 06/07/2006, 15h54
  5. Gestion des accès concurrents à une table
    Par kodo dans le forum SQL Procédural
    Réponses: 1
    Dernier message: 20/06/2006, 14h05

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