[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:
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:
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 ?