Guillaume VIEL :: java jee tomcat linux

Aller au contenu | Aller au menu | Aller à la recherche

mardi 23 août 2011

Audit des requêtes SQL Hibernate

Obtenir les traces des prepared statements d'Hibernate est assez simple et tout le monde connaît cette configuration. Il suffit d'indiquer

hibernate.show_sql=true

dans le fichier de configuration XML Hibernate pour obtenir la requête qui sera utilisé avec le SGBD. La requête sera affichée sous la forme d'un preparedStatement avec des "?" à la place des valeurs.

Une question alors fréquemment posée est : comment obtenir aussi les valeurs passée avec la requête?!

L'information est quelque part connue en interne dans Hibernate : le tout est de la mettre en valeur en modifiant le paramétrage du logger. Par exemple avec log4j il suffit de mettre en level DEBUG les packages suivants et de les router vers un appender spécifique avec une additivité à false :

log4j.logger.org.hibernate.SQL=DEBUG,SQL_APPENDER
log4j.additivity.org.hibernate.SQL=false
org.hibernate.type=DEBUG,SQL_APPENDER
log4j.additivity.org.hibernate.type=false

dimanche 7 novembre 2010

Hibernate interceptor : nom de schéma dynamique

Bien d'Hibernate soit capable d'aller chercher des données dans des tables situées dans différents schémas, il n'est pas possible directement de changer le schéma à l'exécution. En effet, les annotations sont lues à  la compilation et le code d'une @Entity est alors figé sur un schéma et une table.

@Entity
@Table(name="MON_OBJET",schema="MON_SCHEMA")
public class MonObjet implements Serializable {
...
private Etat etat;
...
@OneToOne(...)
public Etat getEtat() { ... }
public void setEtat(Etat etat) { ... }
}

@Entity
@Table(name="ETAT",schema="MON_SCHEMA")
public class Etat {
...
}

Ceci devient gênant lorsque par exemple, une des entités peut se trouver dans différents schémas qui correspondent par exemple à des environnements différents. Par exemple, si MonObject est attaché en relation un à un à un objet Etat qui peut se trouver dans MON_SCHEMA, SCHEMA_PREPROD ou SCHEMA_PROD, on devra alors packager une application par schéma!

Une solution possible serait de créer un profile maven pour chaque environnement, puis d'utiliser la phase de génération des sources pour modifier les annotations dans le code java... Ce qui semble plutôt lourd à mettre en place! Et au final, il faut toujours une application par schéma utilisé! Il existe cependant une solution avec les interceptor d'Hibernate pour ne déployer qu'une seule application...

Lire la suite...

dimanche 21 juin 2009

Statistiques Hibernate et EHCache via JMX grâce à Spring

Récemment, chez un client, nous avons dû mettre en place un cache de données pour améliorer les performances de l'application. Même si l'on peut attendre des gains de la mise en place d'un cache de données EHcache, encore faut il affiner le paramétrage en fonction de l'utilisation réelle de l'application. La seule manière de faire est d'avoir des statistiques sur le cache et les requêtes envoyées à la base de données. Mode d'emploi.

Lire la suite...

mercredi 10 juin 2009

Hibernate sans modèle de données avec du SQL natif et la méthode aliasToBean

Chez un client, je découvre dans un bean des getters / setters en doublon : getMaVariable() et getMAVARIABLE(). Quelle horreur!

Le client m'explique que l'équipe de développement a eu des problèmes avec les noms de colonne Oracle lors de la transformation vers un Bean avec la méthode aliasToBean d'Hibernate, car Oracle renvoit systématiquemen des noms de colonne en majuscule... Les getters / setters ne sont alors pas trouvés.
J'ai finalement trouvé comment remédier au problème et je vous fais profiter de la solution.

String q = "SELECT axe, num_route AS numRoute, pr AS prStart, prfin AS prEnd FROM GRAPHE_AXE WHERE id_ech = :idEch";
SQLQuery hq = session.createSQLQuery(q).addScalar("axe").addScalar("numRoute").addScalar("prStart",Hibernate.DOUBLE).addScalar("prEnd",Hibernate.DOUBLE);
List<AxeRange> axeRanges = (List<AxeRange>) hq.setLong("idEch", idEch).setResultTransformer(Transformers.aliasToBean(AxeRange.class)).list();


La réponse est dans ce post : http://www.mail-archive.com/hibernate-dev@lists.jboss.org/msg01043.html
C'est plus un pb lié à la base de données qu'Hibernate

a) mettre les alias portant le même nom que les membres du bean dans la requête SQL
b) utiliser addScalar sur la SQLQuery initiale avec le même nom d'alias mais en case sensitive (correspondant aux membres du bean résultat): de cette façon un mapping sera fait entre le nom donné dans addScalar et l'alias majuscule renvoyé par Oracle
c) éventuellement forcer aussi les types dans addScalar (pour éviter de récupérer des BigDecimal sur des valeurs entières!)
d) utiliser aliasBean comme d'habitude

Sources : pour l'utilisation des query natives dans Hibernate cf. http://docs.jboss.org/hibernate/stable/core/reference/fr/html/querysql.html