Hibernate
Informations rapides
Session, Entites et cycle de vie
cycle de vie
Il y a trois etats
- Transient (A la creation de l'objet via un new, il est Transient, il disparait a la fin de la methode)
- Persistant (Lorsque l'on le rattache a la session (find, load, persit, merge, …), il devient Persistant)
- Detache (Si la session est fermee, l'objet devient Detache (session.close …)
Session et Entites
La session est le lien avec la base de donnees. Elle remplace la connexion JDBC. Elle est soit ouverte ou fermee.
Il y a une relation Entite * —> 1 session.
Si la session est fermee, les operations sur les l'entites ne seront pas persistée ….
La configuration Eagger charge l'entite avec toutes ces dependances lors du premier appel.
La configuration Lazy permet un chargement on demande, souvent meilleur pour les performances. L'entite est charge en mode very light avec un proxy pour ces dependances (qui contient les cles etrangeres des objets)
Les modes Eagger ou Lazy sont exclusifs dans la configuration.
Si utilisation du design pattern Open Session in View, la session est ouverte dans le filtre JSF et fermee a la fin du post. Les Entites sont toujours detaché.
L'action de flush est appele automatiquement a la fin de chaque transaction. Sinon un flush manuel peut etre appele. Si l'on passe la configuration de l'application totalement en flush manuel, en cas d'oubli rien ne sera persiste en base.
Mapping JPA ou Hibernate
JPA, c'est avec les annotations et l'entity manager.
Hibernate, c'est avec les configuration XML, HBM et les methodes sur la session.
Type de mapping
- one to one : Par defaut, la configuration est en eagger. L'on place la cle etrangere sur l'une des 2 tables
- many to one ou one to many: L'on place la cle etrangere sur la table en many.
- many to many : l'on utilise une table technique intermediaire
HQL et fetching Strategie
L'utilisation du HQL est tres puissant car il permet l'utilisation de fonction comme member of… Hibernate HQL Query
Lors de l'utilisation de la configuration en Lazy, il est possible de charger l'Entite et ces dependances avec le HQL left join fetch, ce qui cree un mode Eagger local.
N+1 Select
En mode Lazy, si l'on boucle sur une liste de dependance pour une entite, Pour chaque element, une requete sera effectue en base. Pour eviter cette perte de temps et de reseau, l'on peut:
- Mettre le mapping en Eagger (pas terrible)
- Faire une requete specifique dans ce cas avec left join fetch pour recuperer toutes les dependances (moyen)
- Utiliser le parametre fetch=“subselect” qui charge la liste de dependances specifiques lors de l'utilisation du premier de la liste.
Le probleme du Transient et le parametre Cascade
Si l'on cree avec un new un objet et une de ces dependances, il faut persiste chaque objet dans le bon ordre. Avec le parametre de mapping Cascade, lors de la persistance de l'un des 2 objets, le second sera persiste automatiquement par hibernate.
Hibernate3
Exemple de code d'hibernate3
HibernateUtil.java
package app.persistance.utils; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.cfg.Environment; import app.persistance.modelObjet; public class HibernateUtil { private static final SessionFactory sessionFactory; static { AnnotationConfiguration annotationConfiguration = new AnnotationConfiguration(); java.util.Properties properties = new java.util.Properties(); properties.put(Environment.DIALECT, "org.hibernate.dialect.Oracle9Dialect"); properties.put("hibernate.connection.driver_class", "oracle.jdbc.driver.OracleDriver"); properties.put("hibernate.connection.url", "jdbc:oracle:thin:@....com:1521:OPUS"); properties.put("hibernate.connection.username", "username"); properties.put("hibernate.connection.password", "password"); properties.put("hibernate.show_sql", "true"); properties.put("hibernate.jdbc.use_streams_for_binary", "true"); annotationConfiguration.setProperties(properties); annotationConfiguration. //addPackage("modelObjet"). addAnnotatedClass( ModelObjet.class); try { sessionFactory = annotationConfiguration.buildSessionFactory(); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } } protected static final ThreadLocal session = new ThreadLocal(); protected static Session currentSession() throws HibernateException { Session s = (Session) session.get(); if (s == null) { s = sessionFactory.openSession(); session.set(s); } return s; } protected static void closeSession() throws HibernateException { Session s = (Session) session.get(); session.set(null); if (s != null) s.close(); } protected static Session getSession() throws HibernateException { return sessionFactory.openSession(); } }
GestionPersistance.java
package app.persistance.utils; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import org.apache.log4j.Logger; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.Transaction; import org.hibernate.criterion.Projections; public class GestionPersistance { public static org.hibernate.Session session; static Logger log = Logger.getLogger(GestionPersistance.class); public GestionPersistance() { try { session = HibernateUtil.currentSession(); } catch ( HibernateException e) { throw e; } } public void closeSession() { try { HibernateUtil.closeSession(); } catch (org.hibernate.HibernateException e) { throw e; } } public static Date dateToLong(java.lang.String dateS) throws Exception { Date date; String format1 = "yyyy-MM-dd KK:mm:ss.SSS"; SimpleDateFormat bartDateFormat = new SimpleDateFormat(format1, Locale.ENGLISH); try { ParsePosition pos = new ParsePosition(0); date = bartDateFormat.parse(dateS, pos); } catch (Exception ex) { log.fatal("Probleme de parsing de date"); System.out.println(ex.getMessage()); throw ex; } return date; } public List requetePeriode (String requete, Date dateD1, Date dateD2,int debut, int fin) throws HibernateException { List list = session.createQuery(requete).setDate(0, dateD1).setDate(1, dateD2) .setFirstResult(debut).setMaxResults(fin).list();; return list; } public List requete( Criteria jobsQuery) throws Exception { Transaction tx = null; List jobsList = new ArrayList(); try { tx = session.beginTransaction(); jobsList = jobsQuery.list(); tx.commit(); } catch (Exception e) { if (tx != null) { log.fatal("Resultat requete null"); try { tx.rollback(); } catch ( HibernateException he) { throw he; } } } finally { try { closeSession(); } catch ( HibernateException e) { throw new HibernateException(e); } } return jobsList; } public Integer count(Criteria jobsCount) { Transaction tx = null; Integer resultCount = new Integer(0); List resultCountList = new ArrayList(); try { tx = session.beginTransaction(); resultCountList = jobsCount.setProjection( Projections.projectionList().add( Projections.rowCount())).list(); resultCount = Integer.parseInt(resultCountList.get(0).toString()); tx.commit(); } catch (Exception e) { if (tx != null) { log.fatal("Resultat requete null"); try { tx.rollback(); } catch ( HibernateException he) { throw he; } } } finally { try { closeSession(); } catch ( HibernateException e) { throw new HibernateException(e); } } return resultCount; } }
JobsServices.java
package app.service.utils; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.log4j.Logger; import org.hibernate.HibernateException; import org.hibernate.criterion.Order; import org.hibernate.criterion.Restrictions; import app.persistance.modelObjet; import persistance.utils.GestionPersistance; public class JobsServices { private GestionPersistance gestionpersistance; private org.hibernate.Criteria jobsQuery; static Logger log = Logger.getLogger(JobsServices.class); public JobsServices() { gestionpersistance = new GestionPersistance(); jobsQuery = GestionPersistance.session.createCriteria(modelObjet.class); } public List requete(ArrayList requeteFiltre, ArrayList requeteFiltreDate, Integer FirstResult, Integer MaxResults, String periodeDebut, String periodeFin, ArrayList orderBy, ArrayList groupBy) { log.info("requete Service"); log.debug("requete => debut"); java.util.List reponse = new java.util.ArrayList(); log.debug("requete => Traitement de la requete"); pagination(FirstResult, MaxResults); traitementPeriode(periodeDebut.trim() + " 00:00:00.0", periodeFin.trim() + " 00:00:00.0"); orderBy(orderBy); filtre(requeteFiltre); filtreDate(requeteFiltreDate); /* groupBy(groupBy); */ try { log.debug("requete => envoie requete"); reponse = gestionpersistance.requete(jobsQuery); log.debug("requete => recuperation requete = " + reponse); log.debug("requete => recuperation reponse.size() = " + reponse.size()); } catch (HibernateException e) { log.fatal("requete => HibernateException"); e.printStackTrace(); } catch (Exception e) { log.fatal("requete => Exception"); e.printStackTrace(); } finally { log.debug("requete => fin"); } return reponse; } public List requete(ArrayList requeteFiltre, ArrayList requeteFiltreDate, Integer FirstResult, Integer MaxResults, String periodeDebut, String periodeFin, ArrayList orderBy) { log.info("requete Service"); log.debug("requete => debut"); List reponse = new ArrayList(); log.debug("requete => Traitement de la requete"); pagination(FirstResult, MaxResults); traitementPeriode(periodeDebut.trim() + " 00:00:00.0", periodeFin.trim() + " 00:00:00.0"); orderBy(orderBy); filtre(requeteFiltre); filtreDate(requeteFiltreDate); try { log.debug("requete => envoie requete"); reponse = gestionpersistance.requete(jobsQuery); log.debug("requete => recuperation requete = " + reponse); log.debug("requete => recuperation reponse.size() = " + reponse.size()); } catch (HibernateException e) { log.fatal("requete => HibernateException"); e.printStackTrace(); } catch (Exception e) { log.fatal("requete => Exception"); e.printStackTrace(); } finally { log.debug("requete => fin"); } return reponse; } public Integer count(ArrayList requeteFiltre, ArrayList requeteFiltreDate, Integer limitInf, Integer limitMax, String periodeDebut, String periodeFin, ArrayList orderBy) { log.info("count Service"); log.debug("count => debut"); Integer reponse = 0; log.debug("count => Traitement de la requete"); traitementPeriode(periodeDebut + " 00:00:00.0", periodeFin + " 00:00:00.0"); filtre(requeteFiltre); filtreDate(requeteFiltreDate); try { log.debug("count => envoie requete"); reponse = gestionpersistance.count(jobsQuery); log.debug("count => recuperation requete = " + reponse); } catch (HibernateException e) { log.fatal("count => HibernateException"); e.printStackTrace(); } catch (Exception e) { log.fatal("count => Exception"); e.printStackTrace(); } finally { log.debug("count => fin"); } return reponse; } private void filtreDate(ArrayList requeteFiltreDate) { log.debug("requete => requeteFiltreDate debut "); log.debug("requete => requeteFiltreDate.size() = " + requeteFiltreDate.size()); if (!requeteFiltreDate.isEmpty()) { for (int i = 0; i < (requeteFiltreDate.size());) { String champ = (String) requeteFiltreDate.get(i++); if (!champ.equals("")) { String filtre = (String) requeteFiltreDate.get(i++); log.debug("requete => requeteFiltreDate ;champ = " + champ + " ; filtre = " + filtre); try { jobsQuery.add(Restrictions.eq(champ, GestionPersistance.dateToLong(filtre))); } catch (Exception e) { log.fatal("requete => dateToLong Exception"); e.printStackTrace(); } } } } log.debug("requete => requeteFiltreDate fin "); } private void filtre(ArrayList requeteFiltre) { log.debug("requete => requeteFiltre debut "); log.debug("requete => requeteFiltre.size() = " + requeteFiltre.size()); if (!requeteFiltre.isEmpty()) { for (int i = 0; i < (requeteFiltre.size());) { String champ = (String) requeteFiltre.get(i++); if (!champ.equals("")) { String filtre = (String) requeteFiltre.get(i++); if (champ.equalsIgnoreCase("id")) { jobsQuery.add(Restrictions.eq(champ, Long.parseLong(filtre.trim()))); log.debug("requete => requeteFiltre ;champ = " + champ + " ;filtre = " + filtre); } else { jobsQuery.add(Restrictions.like(champ, "%" + filtre + "%")); log.debug("requete => requeteFiltre ;champ = " + champ + " ;filtre = " + filtre); } } } } log.debug("requete => requeteFiltre fin "); } private void orderBy(ArrayList orderBy) { log.debug("requete => orderBy debut "); log.debug("requete => orderBy orderBy.size() = " + orderBy.size()); if (!orderBy.isEmpty()) { for (int i = 0; i < orderBy.size();) { String champ = (String) orderBy.get(i++); if (!champ.equals("")) { String sens = (String) orderBy.get(i++); if (sens.equalsIgnoreCase("Asc")) { jobsQuery.addOrder(Order.asc(champ)); log.debug("requete => orderBy asc = " + champ); } else { jobsQuery.addOrder(Order.desc(champ)); log.debug("requete => orderBy desc = " + champ); } } } } log.debug("requete => orderBy fin "); } private void pagination(Integer FirstResult, Integer MaxResults) { log.debug("requete => FirstResult = " + FirstResult); log.debug("requete => MaxResults = " + MaxResults); jobsQuery.setFirstResult(FirstResult).setMaxResults(MaxResults); } private void traitementPeriode(String periodeDebut, String periodeFin) { log.debug("traitementPeriode => debut "); log.debug("traitementPeriode => periodeDebut = " + periodeDebut); log.debug("traitementPeriode => periodeFin = " + periodeFin); Date dateDebut = new java.util.Date(); Date datefin = new java.util.Date(); try { log.debug("traitementPeriode => dateToLong debut"); dateDebut = GestionPersistance.dateToLong(periodeDebut); datefin = GestionPersistance.dateToLong(periodeFin); log.debug("traitementPeriode => dateToLong fin"); } catch (Exception e1) { log.fatal("traitementPeriode => dateToLong Exception"); e1.printStackTrace(); } jobsQuery.add(Restrictions.and(Restrictions.le("startDate", datefin), Restrictions.ge("stopDate", dateDebut))); log.debug("traitementPeriode => fin "); } }